pixel-react 1.15.11 → 1.15.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +75 -75
 - package/lib/ThirdPartyPackages/JanusGateway.js +5 -2
 - package/lib/ThirdPartyPackages/JanusGateway.js.map +1 -1
 - package/lib/_virtual/index10.js +2 -2
 - package/lib/_virtual/index12.js +2 -2
 - package/lib/_virtual/index9.js +2 -2
 - package/lib/assets/icons/spinner.svg.js +1 -1
 - package/lib/assets/icons/spinner.svg.js.map +1 -1
 - package/lib/components/Editor/Editor.js +69 -26
 - package/lib/components/Editor/Editor.js.map +1 -1
 - package/lib/components/Editor/VariableDropdown.js +2 -2
 - package/lib/components/Editor/calculateDropdownPosition.d.ts +7 -0
 - package/lib/components/Editor/calculateDropdownPosition.js +31 -0
 - package/lib/components/Editor/calculateDropdownPosition.js.map +1 -0
 - package/lib/index.cjs +7312 -4600
 - package/lib/index.cjs.map +1 -1
 - package/lib/index.d.ts +2 -1
 - package/lib/index.js +2 -2
 - package/lib/node_modules/@date-fns/tz/date/index.js +19 -1
 - package/lib/node_modules/@date-fns/tz/date/index.js.map +1 -1
 - package/lib/node_modules/@date-fns/tz/date/mini.js +6 -34
 - package/lib/node_modules/@date-fns/tz/date/mini.js.map +1 -1
 - package/lib/node_modules/@date-fns/tz/tzOffset/index.js +5 -6
 - package/lib/node_modules/@date-fns/tz/tzOffset/index.js.map +1 -1
 - package/lib/node_modules/janus-gateway/npm/dist/janus.es.js +3241 -0
 - package/lib/node_modules/janus-gateway/npm/dist/janus.es.js.map +1 -0
 - package/lib/node_modules/js-beautify/js/src/css/beautifier.js +1 -1
 - package/lib/node_modules/js-beautify/js/src/css/index.js +1 -1
 - package/lib/node_modules/js-beautify/js/src/css/options.js +1 -1
 - package/lib/node_modules/js-beautify/js/src/html/beautifier.js +1 -1
 - package/lib/node_modules/js-beautify/js/src/html/index.js +1 -1
 - package/lib/node_modules/js-beautify/js/src/html/options.js +1 -1
 - package/lib/node_modules/js-beautify/js/src/html/tokenizer.js +1 -1
 - package/lib/node_modules/js-beautify/js/src/javascript/beautifier.js +1 -1
 - package/lib/node_modules/js-beautify/js/src/javascript/options.js +1 -1
 - package/lib/node_modules/js-beautify/js/src/javascript/tokenizer.js +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/AsYouType.js +82 -115
 - package/lib/node_modules/libphonenumber-js/es6/AsYouType.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/AsYouTypeFormatter.PatternMatcher.js +58 -68
 - package/lib/node_modules/libphonenumber-js/es6/AsYouTypeFormatter.PatternMatcher.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/AsYouTypeFormatter.PatternParser.js +23 -36
 - package/lib/node_modules/libphonenumber-js/es6/AsYouTypeFormatter.PatternParser.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/AsYouTypeFormatter.complete.js +9 -13
 - package/lib/node_modules/libphonenumber-js/es6/AsYouTypeFormatter.complete.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/AsYouTypeFormatter.js +187 -226
 - package/lib/node_modules/libphonenumber-js/es6/AsYouTypeFormatter.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/AsYouTypeFormatter.util.js +27 -21
 - package/lib/node_modules/libphonenumber-js/es6/AsYouTypeFormatter.util.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/AsYouTypeParser.js +117 -150
 - package/lib/node_modules/libphonenumber-js/es6/AsYouTypeParser.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/AsYouTypeState.js +38 -57
 - package/lib/node_modules/libphonenumber-js/es6/AsYouTypeState.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/ParseError.js +109 -70
 - package/lib/node_modules/libphonenumber-js/es6/ParseError.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/PhoneNumber.js +57 -72
 - package/lib/node_modules/libphonenumber-js/es6/PhoneNumber.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/constants.js +9 -15
 - package/lib/node_modules/libphonenumber-js/es6/constants.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/format.js +93 -67
 - package/lib/node_modules/libphonenumber-js/es6/format.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/formatIncompletePhoneNumber.js +1 -0
 - package/lib/node_modules/libphonenumber-js/es6/formatIncompletePhoneNumber.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/getCountries.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/helpers/RFC3966.js +1 -0
 - package/lib/node_modules/libphonenumber-js/es6/helpers/RFC3966.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/helpers/applyInternationalSeparatorStyle.js +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/helpers/applyInternationalSeparatorStyle.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/helpers/checkNumberLength.js +10 -49
 - package/lib/node_modules/libphonenumber-js/es6/helpers/checkNumberLength.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/helpers/extension/createExtensionPattern.js +32 -20
 - package/lib/node_modules/libphonenumber-js/es6/helpers/extension/createExtensionPattern.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/helpers/extension/extractExtension.js +4 -5
 - package/lib/node_modules/libphonenumber-js/es6/helpers/extension/extractExtension.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/helpers/extractCountryCallingCode.js +18 -25
 - package/lib/node_modules/libphonenumber-js/es6/helpers/extractCountryCallingCode.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/helpers/extractCountryCallingCodeFromInternationalNumberWithoutPlusSign.js +11 -12
 - package/lib/node_modules/libphonenumber-js/es6/helpers/extractCountryCallingCodeFromInternationalNumberWithoutPlusSign.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/helpers/extractFormattedPhoneNumberFromPossibleRfc3966NumberUri.js +11 -13
 - package/lib/node_modules/libphonenumber-js/es6/helpers/extractFormattedPhoneNumberFromPossibleRfc3966NumberUri.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/helpers/extractNationalNumber.js +11 -21
 - package/lib/node_modules/libphonenumber-js/es6/helpers/extractNationalNumber.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/helpers/extractNationalNumberFromPossiblyIncompleteNumber.js +11 -12
 - package/lib/node_modules/libphonenumber-js/es6/helpers/extractNationalNumberFromPossiblyIncompleteNumber.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/helpers/extractPhoneContext.js +12 -15
 - package/lib/node_modules/libphonenumber-js/es6/helpers/extractPhoneContext.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/helpers/formatNationalNumberUsingFormat.js +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/helpers/formatNationalNumberUsingFormat.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/helpers/getCountryByCallingCode.js +4 -4
 - package/lib/node_modules/libphonenumber-js/es6/helpers/getCountryByCallingCode.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/helpers/getCountryByNationalNumber.js +35 -59
 - package/lib/node_modules/libphonenumber-js/es6/helpers/getCountryByNationalNumber.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/helpers/getIddPrefix.js +2 -2
 - package/lib/node_modules/libphonenumber-js/es6/helpers/getIddPrefix.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/helpers/getNumberType.js +36 -38
 - package/lib/node_modules/libphonenumber-js/es6/helpers/getNumberType.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/helpers/getPossibleCountriesForNumber.js +1 -0
 - package/lib/node_modules/libphonenumber-js/es6/helpers/getPossibleCountriesForNumber.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/helpers/isObject.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/helpers/isViablePhoneNumber.js +10 -14
 - package/lib/node_modules/libphonenumber-js/es6/helpers/isViablePhoneNumber.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/helpers/matchesEntirely.js +4 -4
 - package/lib/node_modules/libphonenumber-js/es6/helpers/matchesEntirely.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/helpers/parseDigits.js +27 -22
 - package/lib/node_modules/libphonenumber-js/es6/helpers/parseDigits.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/helpers/stripIddPrefix.js +6 -6
 - package/lib/node_modules/libphonenumber-js/es6/helpers/stripIddPrefix.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/isPossible.js +7 -6
 - package/lib/node_modules/libphonenumber-js/es6/isPossible.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/isValid.js +5 -6
 - package/lib/node_modules/libphonenumber-js/es6/isValid.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/isValidPhoneNumber.js +26 -44
 - package/lib/node_modules/libphonenumber-js/es6/isValidPhoneNumber.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/metadata.js +69 -120
 - package/lib/node_modules/libphonenumber-js/es6/metadata.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/normalizeArguments.js +68 -87
 - package/lib/node_modules/libphonenumber-js/es6/normalizeArguments.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/parse.js +40 -58
 - package/lib/node_modules/libphonenumber-js/es6/parse.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/parseIncompletePhoneNumber.js +36 -32
 - package/lib/node_modules/libphonenumber-js/es6/parseIncompletePhoneNumber.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/parsePhoneNumber.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/parsePhoneNumberWithError_.js +26 -44
 - package/lib/node_modules/libphonenumber-js/es6/parsePhoneNumberWithError_.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/parsePhoneNumber_.js +28 -46
 - package/lib/node_modules/libphonenumber-js/es6/parsePhoneNumber_.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/es6/tools/semver-compare.js.map +1 -1
 - package/lib/node_modules/libphonenumber-js/metadata.min.json.js +18 -18
 - package/lib/node_modules/libphonenumber-js/metadata.min.json.js.map +1 -1
 - package/lib/node_modules/prop-types/index.js +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/DayPicker.js +64 -88
 - package/lib/node_modules/react-day-picker/dist/esm/DayPicker.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/UI.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/classes/CalendarDay.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/classes/CalendarMonth.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/classes/CalendarWeek.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/classes/DateLib.js +6 -71
 - package/lib/node_modules/react-day-picker/dist/esm/classes/DateLib.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/components/Button.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/components/CaptionLabel.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/components/Chevron.js +14 -18
 - package/lib/node_modules/react-day-picker/dist/esm/components/Chevron.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/components/Day.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/components/DayButton.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/components/Dropdown.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/components/DropdownNav.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/components/Footer.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/components/Month.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/components/MonthCaption.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/components/MonthGrid.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/components/Months.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/components/MonthsDropdown.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/components/Nav.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/components/NextMonthButton.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/components/Option.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/components/PreviousMonthButton.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/components/Root.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/components/Select.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/components/Week.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/components/WeekNumber.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/components/WeekNumberHeader.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/components/Weekday.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/components/Weekdays.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/components/Weeks.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/components/YearsDropdown.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/formatters/formatCaption.js +2 -3
 - package/lib/node_modules/react-day-picker/dist/esm/formatters/formatCaption.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/formatters/formatDay.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/formatters/formatMonthDropdown.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/formatters/formatWeekNumber.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/formatters/formatWeekNumberHeader.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/formatters/formatWeekdayName.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/formatters/formatYearDropdown.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/formatters/index.js +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/helpers/calculateFocusTarget.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/helpers/createGetModifiers.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/helpers/endOfBroadcastWeek.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/helpers/getBroadcastWeeksInMonth.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/helpers/getClassNamesForModifiers.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/helpers/getComponents.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/helpers/getDataAttributes.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/helpers/getDates.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/helpers/getDays.js +4 -4
 - package/lib/node_modules/react-day-picker/dist/esm/helpers/getDays.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/helpers/getDefaultClassNames.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/helpers/getDisplayMonths.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/helpers/getFocusableDate.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/helpers/getFormatters.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/helpers/getInitialMonth.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/helpers/getMonthOptions.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/helpers/getMonths.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/helpers/getNavMonth.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/helpers/getNextFocus.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/helpers/getNextMonth.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/helpers/getPreviousMonth.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/helpers/getStyleForModifiers.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/helpers/getWeekdays.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/helpers/getWeeks.js +2 -2
 - package/lib/node_modules/react-day-picker/dist/esm/helpers/getWeeks.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/helpers/getYearOptions.js +11 -9
 - package/lib/node_modules/react-day-picker/dist/esm/helpers/getYearOptions.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/helpers/startOfBroadcastWeek.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/helpers/useControlledValue.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/labels/index.js +2 -2
 - package/lib/node_modules/react-day-picker/dist/esm/labels/labelDayButton.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/labels/labelGrid.js +2 -3
 - package/lib/node_modules/react-day-picker/dist/esm/labels/labelGrid.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/labels/labelGridcell.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/labels/labelMonthDropdown.js +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/labels/labelMonthDropdown.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/labels/labelNav.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/labels/labelNext.js +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/labels/labelNext.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/labels/labelPrevious.js +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/labels/labelPrevious.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/labels/labelWeekNumber.js +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/labels/labelWeekNumber.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/labels/labelWeekNumberHeader.js +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/labels/labelWeekNumberHeader.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/labels/labelWeekday.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/labels/labelYearDropdown.js +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/labels/labelYearDropdown.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/selection/useMulti.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/selection/useRange.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/selection/useSingle.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/useAnimation.js +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/useAnimation.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/useCalendar.js +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/useCalendar.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/useDayPicker.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/useFocus.js +0 -6
 - package/lib/node_modules/react-day-picker/dist/esm/useFocus.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/useSelection.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/utils/addToRange.js +1 -6
 - package/lib/node_modules/react-day-picker/dist/esm/utils/addToRange.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/utils/dateMatchModifiers.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/utils/rangeContainsDayOfWeek.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/utils/rangeContainsModifiers.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/utils/rangeIncludesDate.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/utils/rangeOverlaps.js.map +1 -1
 - package/lib/node_modules/react-day-picker/dist/esm/utils/typeguards.js.map +1 -1
 - package/lib/node_modules/react-hook-form/dist/index.esm.js +44 -67
 - package/lib/node_modules/react-hook-form/dist/index.esm.js.map +1 -1
 - package/lib/node_modules/react-virtuoso/dist/index.js +1200 -1246
 - package/lib/node_modules/react-virtuoso/dist/index.js.map +1 -1
 - package/lib/node_modules/ua-parser-js/src/ua-parser.js +71 -85
 - package/lib/node_modules/ua-parser-js/src/ua-parser.js.map +1 -1
 - package/lib/styles.css +1 -1
 - package/lib/styles.css.map +1 -1
 - package/lib/tsconfig.tsbuildinfo +1 -1
 - package/lib/validations/regex.js +6 -1
 - package/lib/validations/regex.js.map +1 -1
 - package/package.json +106 -106
 - package/lib/node_modules/@date-fns/tz/tzName/index.js +0 -40
 - package/lib/node_modules/@date-fns/tz/tzName/index.js.map +0 -1
 - package/lib/node_modules/react-day-picker/node_modules/date-fns/eachYearOfInterval.js +0 -64
 - package/lib/node_modules/react-day-picker/node_modules/date-fns/eachYearOfInterval.js.map +0 -1
 
| 
         @@ -0,0 +1,3241 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            /*
         
     | 
| 
      
 2 
     | 
    
         
            +
            	The MIT License (MIT)
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            	Copyright (c) 2016 Meetecho
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            	Permission is hereby granted, free of charge, to any person obtaining
         
     | 
| 
      
 7 
     | 
    
         
            +
            	a copy of this software and associated documentation files (the "Software"),
         
     | 
| 
      
 8 
     | 
    
         
            +
            	to deal in the Software without restriction, including without limitation
         
     | 
| 
      
 9 
     | 
    
         
            +
            	the rights to use, copy, modify, merge, publish, distribute, sublicense,
         
     | 
| 
      
 10 
     | 
    
         
            +
            	and/or sell copies of the Software, and to permit persons to whom the
         
     | 
| 
      
 11 
     | 
    
         
            +
            	Software is furnished to do so, subject to the following conditions:
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            	The above copyright notice and this permission notice shall be included
         
     | 
| 
      
 14 
     | 
    
         
            +
            	in all copies or substantial portions of the Software.
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
         
     | 
| 
      
 17 
     | 
    
         
            +
            	OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
         
     | 
| 
      
 18 
     | 
    
         
            +
            	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
         
     | 
| 
      
 19 
     | 
    
         
            +
            	THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
         
     | 
| 
      
 20 
     | 
    
         
            +
            	OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
         
     | 
| 
      
 21 
     | 
    
         
            +
            	ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
         
     | 
| 
      
 22 
     | 
    
         
            +
            	OTHER DEALINGS IN THE SOFTWARE.
         
     | 
| 
      
 23 
     | 
    
         
            +
             */
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            // eslint-disable-next-line no-unused-vars
         
     | 
| 
      
 26 
     | 
    
         
            +
            var Janus = function (factory) {
         
     | 
| 
      
 27 
     | 
    
         
            +
              if (typeof define === 'function' && define.amd) {
         
     | 
| 
      
 28 
     | 
    
         
            +
                define(factory);
         
     | 
| 
      
 29 
     | 
    
         
            +
              } else if (typeof module === 'object' && module.exports) {
         
     | 
| 
      
 30 
     | 
    
         
            +
                module.exports = factory();
         
     | 
| 
      
 31 
     | 
    
         
            +
              } else if (typeof window === 'object') {
         
     | 
| 
      
 32 
     | 
    
         
            +
                return factory();
         
     | 
| 
      
 33 
     | 
    
         
            +
              }
         
     | 
| 
      
 34 
     | 
    
         
            +
            }(function () {
         
     | 
| 
      
 35 
     | 
    
         
            +
              // List of sessions
         
     | 
| 
      
 36 
     | 
    
         
            +
              Janus.sessions = new Map();
         
     | 
| 
      
 37 
     | 
    
         
            +
              Janus.isExtensionEnabled = function () {
         
     | 
| 
      
 38 
     | 
    
         
            +
                if (navigator.mediaDevices && navigator.mediaDevices.getDisplayMedia) {
         
     | 
| 
      
 39 
     | 
    
         
            +
                  // No need for the extension, getDisplayMedia is supported
         
     | 
| 
      
 40 
     | 
    
         
            +
                  return true;
         
     | 
| 
      
 41 
     | 
    
         
            +
                }
         
     | 
| 
      
 42 
     | 
    
         
            +
                if (window.navigator.userAgent.match('Chrome')) {
         
     | 
| 
      
 43 
     | 
    
         
            +
                  let chromever = parseInt(window.navigator.userAgent.match(/Chrome\/(.*) /)[1], 10);
         
     | 
| 
      
 44 
     | 
    
         
            +
                  let maxver = 33;
         
     | 
| 
      
 45 
     | 
    
         
            +
                  if (window.navigator.userAgent.match('Linux')) maxver = 35; // "known" crash in chrome 34 and 35 on linux
         
     | 
| 
      
 46 
     | 
    
         
            +
                  if (chromever >= 26 && chromever <= maxver) {
         
     | 
| 
      
 47 
     | 
    
         
            +
                    // Older versions of Chrome don't support this extension-based approach, so lie
         
     | 
| 
      
 48 
     | 
    
         
            +
                    return true;
         
     | 
| 
      
 49 
     | 
    
         
            +
                  }
         
     | 
| 
      
 50 
     | 
    
         
            +
                  return Janus.extension.isInstalled();
         
     | 
| 
      
 51 
     | 
    
         
            +
                } else {
         
     | 
| 
      
 52 
     | 
    
         
            +
                  // Firefox and others, no need for the extension (but this doesn't mean it will work)
         
     | 
| 
      
 53 
     | 
    
         
            +
                  return true;
         
     | 
| 
      
 54 
     | 
    
         
            +
                }
         
     | 
| 
      
 55 
     | 
    
         
            +
              };
         
     | 
| 
      
 56 
     | 
    
         
            +
              var defaultExtension = {
         
     | 
| 
      
 57 
     | 
    
         
            +
                // Screensharing Chrome Extension ID
         
     | 
| 
      
 58 
     | 
    
         
            +
                extensionId: 'hapfgfdkleiggjjpfpenajgdnfckjpaj',
         
     | 
| 
      
 59 
     | 
    
         
            +
                isInstalled: function () {
         
     | 
| 
      
 60 
     | 
    
         
            +
                  return document.querySelector('#janus-extension-installed') !== null;
         
     | 
| 
      
 61 
     | 
    
         
            +
                },
         
     | 
| 
      
 62 
     | 
    
         
            +
                getScreen: function (callback) {
         
     | 
| 
      
 63 
     | 
    
         
            +
                  let pending = window.setTimeout(function () {
         
     | 
| 
      
 64 
     | 
    
         
            +
                    let error = new Error('NavigatorUserMediaError');
         
     | 
| 
      
 65 
     | 
    
         
            +
                    error.name = 'The required Chrome extension is not installed: click <a href="#">here</a> to install it. (NOTE: this will need you to refresh the page)';
         
     | 
| 
      
 66 
     | 
    
         
            +
                    return callback(error);
         
     | 
| 
      
 67 
     | 
    
         
            +
                  }, 1000);
         
     | 
| 
      
 68 
     | 
    
         
            +
                  this.cache[pending] = callback;
         
     | 
| 
      
 69 
     | 
    
         
            +
                  window.postMessage({
         
     | 
| 
      
 70 
     | 
    
         
            +
                    type: 'janusGetScreen',
         
     | 
| 
      
 71 
     | 
    
         
            +
                    id: pending
         
     | 
| 
      
 72 
     | 
    
         
            +
                  }, '*');
         
     | 
| 
      
 73 
     | 
    
         
            +
                },
         
     | 
| 
      
 74 
     | 
    
         
            +
                init: function () {
         
     | 
| 
      
 75 
     | 
    
         
            +
                  let cache = {};
         
     | 
| 
      
 76 
     | 
    
         
            +
                  this.cache = cache;
         
     | 
| 
      
 77 
     | 
    
         
            +
                  // Wait for events from the Chrome Extension
         
     | 
| 
      
 78 
     | 
    
         
            +
                  window.addEventListener('message', function (event) {
         
     | 
| 
      
 79 
     | 
    
         
            +
                    if (event.origin != window.location.origin) return;
         
     | 
| 
      
 80 
     | 
    
         
            +
                    if (event.data.type == 'janusGotScreen' && cache[event.data.id]) {
         
     | 
| 
      
 81 
     | 
    
         
            +
                      let callback = cache[event.data.id];
         
     | 
| 
      
 82 
     | 
    
         
            +
                      delete cache[event.data.id];
         
     | 
| 
      
 83 
     | 
    
         
            +
                      if (event.data.sourceId === '') {
         
     | 
| 
      
 84 
     | 
    
         
            +
                        // user canceled
         
     | 
| 
      
 85 
     | 
    
         
            +
                        let error = new Error('NavigatorUserMediaError');
         
     | 
| 
      
 86 
     | 
    
         
            +
                        error.name = 'You cancelled the request for permission, giving up...';
         
     | 
| 
      
 87 
     | 
    
         
            +
                        callback(error);
         
     | 
| 
      
 88 
     | 
    
         
            +
                      } else {
         
     | 
| 
      
 89 
     | 
    
         
            +
                        callback(null, event.data.sourceId);
         
     | 
| 
      
 90 
     | 
    
         
            +
                      }
         
     | 
| 
      
 91 
     | 
    
         
            +
                    } else if (event.data.type == 'janusGetScreenPending') {
         
     | 
| 
      
 92 
     | 
    
         
            +
                      window.clearTimeout(event.data.id);
         
     | 
| 
      
 93 
     | 
    
         
            +
                    }
         
     | 
| 
      
 94 
     | 
    
         
            +
                  });
         
     | 
| 
      
 95 
     | 
    
         
            +
                }
         
     | 
| 
      
 96 
     | 
    
         
            +
              };
         
     | 
| 
      
 97 
     | 
    
         
            +
              Janus.useDefaultDependencies = function (deps) {
         
     | 
| 
      
 98 
     | 
    
         
            +
                let f = deps && deps.fetch || fetch;
         
     | 
| 
      
 99 
     | 
    
         
            +
                let p = deps && deps.Promise || Promise;
         
     | 
| 
      
 100 
     | 
    
         
            +
                let socketCls = deps && deps.WebSocket || WebSocket;
         
     | 
| 
      
 101 
     | 
    
         
            +
                return {
         
     | 
| 
      
 102 
     | 
    
         
            +
                  newWebSocket: function (server, proto) {
         
     | 
| 
      
 103 
     | 
    
         
            +
                    return new socketCls(server, proto);
         
     | 
| 
      
 104 
     | 
    
         
            +
                  },
         
     | 
| 
      
 105 
     | 
    
         
            +
                  extension: deps && deps.extension || defaultExtension,
         
     | 
| 
      
 106 
     | 
    
         
            +
                  isArray: function (arr) {
         
     | 
| 
      
 107 
     | 
    
         
            +
                    return Array.isArray(arr);
         
     | 
| 
      
 108 
     | 
    
         
            +
                  },
         
     | 
| 
      
 109 
     | 
    
         
            +
                  webRTCAdapter: deps && deps.adapter || adapter,
         
     | 
| 
      
 110 
     | 
    
         
            +
                  httpAPICall: function (url, options) {
         
     | 
| 
      
 111 
     | 
    
         
            +
                    let fetchOptions = {
         
     | 
| 
      
 112 
     | 
    
         
            +
                      method: options.verb,
         
     | 
| 
      
 113 
     | 
    
         
            +
                      headers: {
         
     | 
| 
      
 114 
     | 
    
         
            +
                        'Accept': 'application/json, text/plain, */*'
         
     | 
| 
      
 115 
     | 
    
         
            +
                      },
         
     | 
| 
      
 116 
     | 
    
         
            +
                      cache: 'no-cache'
         
     | 
| 
      
 117 
     | 
    
         
            +
                    };
         
     | 
| 
      
 118 
     | 
    
         
            +
                    if (options.verb === "POST") {
         
     | 
| 
      
 119 
     | 
    
         
            +
                      fetchOptions.headers['Content-Type'] = 'application/json';
         
     | 
| 
      
 120 
     | 
    
         
            +
                    }
         
     | 
| 
      
 121 
     | 
    
         
            +
                    if (typeof options.withCredentials !== 'undefined') {
         
     | 
| 
      
 122 
     | 
    
         
            +
                      fetchOptions.credentials = options.withCredentials === true ? 'include' : options.withCredentials ? options.withCredentials : 'omit';
         
     | 
| 
      
 123 
     | 
    
         
            +
                    }
         
     | 
| 
      
 124 
     | 
    
         
            +
                    if (options.body) {
         
     | 
| 
      
 125 
     | 
    
         
            +
                      fetchOptions.body = JSON.stringify(options.body);
         
     | 
| 
      
 126 
     | 
    
         
            +
                    }
         
     | 
| 
      
 127 
     | 
    
         
            +
                    let fetching = f(url, fetchOptions).catch(function (error) {
         
     | 
| 
      
 128 
     | 
    
         
            +
                      return p.reject({
         
     | 
| 
      
 129 
     | 
    
         
            +
                        message: 'Probably a network error, is the server down?',
         
     | 
| 
      
 130 
     | 
    
         
            +
                        error: error
         
     | 
| 
      
 131 
     | 
    
         
            +
                      });
         
     | 
| 
      
 132 
     | 
    
         
            +
                    });
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
                    /*
         
     | 
| 
      
 135 
     | 
    
         
            +
                    * fetch() does not natively support timeouts.
         
     | 
| 
      
 136 
     | 
    
         
            +
                    * Work around this by starting a timeout manually, and racing it agains the fetch() to see which thing resolves first.
         
     | 
| 
      
 137 
     | 
    
         
            +
                    */
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
                    if (options.timeout) {
         
     | 
| 
      
 140 
     | 
    
         
            +
                      // eslint-disable-next-line no-unused-vars
         
     | 
| 
      
 141 
     | 
    
         
            +
                      let timeout = new p(function (resolve, reject) {
         
     | 
| 
      
 142 
     | 
    
         
            +
                        let timerId = setTimeout(function () {
         
     | 
| 
      
 143 
     | 
    
         
            +
                          clearTimeout(timerId);
         
     | 
| 
      
 144 
     | 
    
         
            +
                          return reject({
         
     | 
| 
      
 145 
     | 
    
         
            +
                            message: 'Request timed out',
         
     | 
| 
      
 146 
     | 
    
         
            +
                            timeout: options.timeout
         
     | 
| 
      
 147 
     | 
    
         
            +
                          });
         
     | 
| 
      
 148 
     | 
    
         
            +
                        }, options.timeout);
         
     | 
| 
      
 149 
     | 
    
         
            +
                      });
         
     | 
| 
      
 150 
     | 
    
         
            +
                      fetching = p.race([fetching, timeout]);
         
     | 
| 
      
 151 
     | 
    
         
            +
                    }
         
     | 
| 
      
 152 
     | 
    
         
            +
                    fetching.then(function (response) {
         
     | 
| 
      
 153 
     | 
    
         
            +
                      if (response.ok) {
         
     | 
| 
      
 154 
     | 
    
         
            +
                        if (typeof options.success === typeof Janus.noop) {
         
     | 
| 
      
 155 
     | 
    
         
            +
                          return response.json().then(function (parsed) {
         
     | 
| 
      
 156 
     | 
    
         
            +
                            try {
         
     | 
| 
      
 157 
     | 
    
         
            +
                              options.success(parsed);
         
     | 
| 
      
 158 
     | 
    
         
            +
                            } catch (error) {
         
     | 
| 
      
 159 
     | 
    
         
            +
                              Janus.error('Unhandled httpAPICall success callback error', error);
         
     | 
| 
      
 160 
     | 
    
         
            +
                            }
         
     | 
| 
      
 161 
     | 
    
         
            +
                          }, function (error) {
         
     | 
| 
      
 162 
     | 
    
         
            +
                            return p.reject({
         
     | 
| 
      
 163 
     | 
    
         
            +
                              message: 'Failed to parse response body',
         
     | 
| 
      
 164 
     | 
    
         
            +
                              error: error,
         
     | 
| 
      
 165 
     | 
    
         
            +
                              response: response
         
     | 
| 
      
 166 
     | 
    
         
            +
                            });
         
     | 
| 
      
 167 
     | 
    
         
            +
                          });
         
     | 
| 
      
 168 
     | 
    
         
            +
                        }
         
     | 
| 
      
 169 
     | 
    
         
            +
                      } else {
         
     | 
| 
      
 170 
     | 
    
         
            +
                        return p.reject({
         
     | 
| 
      
 171 
     | 
    
         
            +
                          message: 'API call failed',
         
     | 
| 
      
 172 
     | 
    
         
            +
                          response: response
         
     | 
| 
      
 173 
     | 
    
         
            +
                        });
         
     | 
| 
      
 174 
     | 
    
         
            +
                      }
         
     | 
| 
      
 175 
     | 
    
         
            +
                    }).catch(function (error) {
         
     | 
| 
      
 176 
     | 
    
         
            +
                      if (typeof options.error === typeof Janus.noop) {
         
     | 
| 
      
 177 
     | 
    
         
            +
                        options.error(error.message || '<< internal error >>', error);
         
     | 
| 
      
 178 
     | 
    
         
            +
                      }
         
     | 
| 
      
 179 
     | 
    
         
            +
                    });
         
     | 
| 
      
 180 
     | 
    
         
            +
                    return fetching;
         
     | 
| 
      
 181 
     | 
    
         
            +
                  }
         
     | 
| 
      
 182 
     | 
    
         
            +
                };
         
     | 
| 
      
 183 
     | 
    
         
            +
              };
         
     | 
| 
      
 184 
     | 
    
         
            +
              Janus.useOldDependencies = function (deps) {
         
     | 
| 
      
 185 
     | 
    
         
            +
                let jq = deps && deps.jQuery || jQuery;
         
     | 
| 
      
 186 
     | 
    
         
            +
                let socketCls = deps && deps.WebSocket || WebSocket;
         
     | 
| 
      
 187 
     | 
    
         
            +
                return {
         
     | 
| 
      
 188 
     | 
    
         
            +
                  newWebSocket: function (server, proto) {
         
     | 
| 
      
 189 
     | 
    
         
            +
                    return new socketCls(server, proto);
         
     | 
| 
      
 190 
     | 
    
         
            +
                  },
         
     | 
| 
      
 191 
     | 
    
         
            +
                  isArray: function (arr) {
         
     | 
| 
      
 192 
     | 
    
         
            +
                    return jq.isArray(arr);
         
     | 
| 
      
 193 
     | 
    
         
            +
                  },
         
     | 
| 
      
 194 
     | 
    
         
            +
                  extension: deps && deps.extension || defaultExtension,
         
     | 
| 
      
 195 
     | 
    
         
            +
                  webRTCAdapter: deps && deps.adapter || adapter,
         
     | 
| 
      
 196 
     | 
    
         
            +
                  httpAPICall: function (url, options) {
         
     | 
| 
      
 197 
     | 
    
         
            +
                    let payload = typeof options.body !== 'undefined' ? {
         
     | 
| 
      
 198 
     | 
    
         
            +
                      contentType: 'application/json',
         
     | 
| 
      
 199 
     | 
    
         
            +
                      data: JSON.stringify(options.body)
         
     | 
| 
      
 200 
     | 
    
         
            +
                    } : {};
         
     | 
| 
      
 201 
     | 
    
         
            +
                    let credentials = typeof options.withCredentials !== 'undefined' ? {
         
     | 
| 
      
 202 
     | 
    
         
            +
                      xhrFields: {
         
     | 
| 
      
 203 
     | 
    
         
            +
                        withCredentials: options.withCredentials
         
     | 
| 
      
 204 
     | 
    
         
            +
                      }
         
     | 
| 
      
 205 
     | 
    
         
            +
                    } : {};
         
     | 
| 
      
 206 
     | 
    
         
            +
                    return jq.ajax(jq.extend(payload, credentials, {
         
     | 
| 
      
 207 
     | 
    
         
            +
                      url: url,
         
     | 
| 
      
 208 
     | 
    
         
            +
                      type: options.verb,
         
     | 
| 
      
 209 
     | 
    
         
            +
                      cache: false,
         
     | 
| 
      
 210 
     | 
    
         
            +
                      dataType: 'json',
         
     | 
| 
      
 211 
     | 
    
         
            +
                      async: options.async,
         
     | 
| 
      
 212 
     | 
    
         
            +
                      timeout: options.timeout,
         
     | 
| 
      
 213 
     | 
    
         
            +
                      success: function (result) {
         
     | 
| 
      
 214 
     | 
    
         
            +
                        if (typeof options.success === typeof Janus.noop) {
         
     | 
| 
      
 215 
     | 
    
         
            +
                          options.success(result);
         
     | 
| 
      
 216 
     | 
    
         
            +
                        }
         
     | 
| 
      
 217 
     | 
    
         
            +
                      },
         
     | 
| 
      
 218 
     | 
    
         
            +
                      // eslint-disable-next-line no-unused-vars
         
     | 
| 
      
 219 
     | 
    
         
            +
                      error: function (xhr, status, err) {
         
     | 
| 
      
 220 
     | 
    
         
            +
                        if (typeof options.error === typeof Janus.noop) {
         
     | 
| 
      
 221 
     | 
    
         
            +
                          options.error(status, err);
         
     | 
| 
      
 222 
     | 
    
         
            +
                        }
         
     | 
| 
      
 223 
     | 
    
         
            +
                      }
         
     | 
| 
      
 224 
     | 
    
         
            +
                    }));
         
     | 
| 
      
 225 
     | 
    
         
            +
                  }
         
     | 
| 
      
 226 
     | 
    
         
            +
                };
         
     | 
| 
      
 227 
     | 
    
         
            +
              };
         
     | 
| 
      
 228 
     | 
    
         
            +
             
     | 
| 
      
 229 
     | 
    
         
            +
              // Helper function to convert a deprecated media object to a tracks array
         
     | 
| 
      
 230 
     | 
    
         
            +
              Janus.mediaToTracks = function (media) {
         
     | 
| 
      
 231 
     | 
    
         
            +
                let tracks = [];
         
     | 
| 
      
 232 
     | 
    
         
            +
                if (!media) {
         
     | 
| 
      
 233 
     | 
    
         
            +
                  // Default is bidirectional audio and video, using default devices
         
     | 
| 
      
 234 
     | 
    
         
            +
                  tracks.push({
         
     | 
| 
      
 235 
     | 
    
         
            +
                    type: 'audio',
         
     | 
| 
      
 236 
     | 
    
         
            +
                    capture: true,
         
     | 
| 
      
 237 
     | 
    
         
            +
                    recv: true
         
     | 
| 
      
 238 
     | 
    
         
            +
                  });
         
     | 
| 
      
 239 
     | 
    
         
            +
                  tracks.push({
         
     | 
| 
      
 240 
     | 
    
         
            +
                    type: 'video',
         
     | 
| 
      
 241 
     | 
    
         
            +
                    capture: true,
         
     | 
| 
      
 242 
     | 
    
         
            +
                    recv: true
         
     | 
| 
      
 243 
     | 
    
         
            +
                  });
         
     | 
| 
      
 244 
     | 
    
         
            +
                } else {
         
     | 
| 
      
 245 
     | 
    
         
            +
                  if (!media.keepAudio && media.audio !== false && (typeof media.audio === 'undefined' || media.audio || media.audioSend || media.audioRecv || media.addAudio || media.replaceAudio || media.removeAudio)) {
         
     | 
| 
      
 246 
     | 
    
         
            +
                    // We may need an audio track
         
     | 
| 
      
 247 
     | 
    
         
            +
                    let track = {
         
     | 
| 
      
 248 
     | 
    
         
            +
                      type: 'audio'
         
     | 
| 
      
 249 
     | 
    
         
            +
                    };
         
     | 
| 
      
 250 
     | 
    
         
            +
                    if (media.removeAudio) {
         
     | 
| 
      
 251 
     | 
    
         
            +
                      track.remove = true;
         
     | 
| 
      
 252 
     | 
    
         
            +
                    } else {
         
     | 
| 
      
 253 
     | 
    
         
            +
                      if (media.addAudio) track.add = true;else if (media.replaceAudio) track.replace = true;
         
     | 
| 
      
 254 
     | 
    
         
            +
                      // Check if we need to capture an audio device
         
     | 
| 
      
 255 
     | 
    
         
            +
                      if (media.audioSend !== false) track.capture = media.audio || true;
         
     | 
| 
      
 256 
     | 
    
         
            +
                      // Check if we need to receive audio
         
     | 
| 
      
 257 
     | 
    
         
            +
                      if (media.audioRecv !== false) track.recv = true;
         
     | 
| 
      
 258 
     | 
    
         
            +
                    }
         
     | 
| 
      
 259 
     | 
    
         
            +
                    // Add an audio track if needed
         
     | 
| 
      
 260 
     | 
    
         
            +
                    if (track.remove || track.capture || track.recv) tracks.push(track);
         
     | 
| 
      
 261 
     | 
    
         
            +
                  }
         
     | 
| 
      
 262 
     | 
    
         
            +
                  if (!media.keepVideo && media.video !== false && (typeof media.video === 'undefined' || media.video || media.videoSend || media.videoRecv || media.addVideo || media.replaceVideo || media.removeVideo)) {
         
     | 
| 
      
 263 
     | 
    
         
            +
                    // We may need a video track
         
     | 
| 
      
 264 
     | 
    
         
            +
                    let track = {
         
     | 
| 
      
 265 
     | 
    
         
            +
                      type: 'video'
         
     | 
| 
      
 266 
     | 
    
         
            +
                    };
         
     | 
| 
      
 267 
     | 
    
         
            +
                    if (media.removeVideo) {
         
     | 
| 
      
 268 
     | 
    
         
            +
                      track.remove = true;
         
     | 
| 
      
 269 
     | 
    
         
            +
                    } else {
         
     | 
| 
      
 270 
     | 
    
         
            +
                      if (media.addVideo) track.add = true;else if (media.replaceVideo) track.replace = true;
         
     | 
| 
      
 271 
     | 
    
         
            +
                      // Check if we need to capture a video device
         
     | 
| 
      
 272 
     | 
    
         
            +
                      if (media.videoSend !== false) {
         
     | 
| 
      
 273 
     | 
    
         
            +
                        track.capture = media.video || true;
         
     | 
| 
      
 274 
     | 
    
         
            +
                        if (['screen', 'window', 'desktop'].includes(track.capture)) {
         
     | 
| 
      
 275 
     | 
    
         
            +
                          // Change the type to 'screen'
         
     | 
| 
      
 276 
     | 
    
         
            +
                          track.type = 'screen';
         
     | 
| 
      
 277 
     | 
    
         
            +
                          track.capture = {
         
     | 
| 
      
 278 
     | 
    
         
            +
                            video: {}
         
     | 
| 
      
 279 
     | 
    
         
            +
                          };
         
     | 
| 
      
 280 
     | 
    
         
            +
                          // Check if there's constraints
         
     | 
| 
      
 281 
     | 
    
         
            +
                          if (media.screenshareFrameRate) track.capture.frameRate = media.screenshareFrameRate;
         
     | 
| 
      
 282 
     | 
    
         
            +
                          if (media.screenshareHeight) track.capture.height = media.screenshareHeight;
         
     | 
| 
      
 283 
     | 
    
         
            +
                          if (media.screenshareWidth) track.capture.width = media.screenshareWidth;
         
     | 
| 
      
 284 
     | 
    
         
            +
                        }
         
     | 
| 
      
 285 
     | 
    
         
            +
                      }
         
     | 
| 
      
 286 
     | 
    
         
            +
                      // Check if we need to receive video
         
     | 
| 
      
 287 
     | 
    
         
            +
                      if (media.videoRecv !== false) track.recv = true;
         
     | 
| 
      
 288 
     | 
    
         
            +
                    }
         
     | 
| 
      
 289 
     | 
    
         
            +
                    // Add a video track if needed
         
     | 
| 
      
 290 
     | 
    
         
            +
                    if (track.remove || track.capture || track.recv) tracks.push(track);
         
     | 
| 
      
 291 
     | 
    
         
            +
                  }
         
     | 
| 
      
 292 
     | 
    
         
            +
                  if (media.data) {
         
     | 
| 
      
 293 
     | 
    
         
            +
                    // We need a data channel
         
     | 
| 
      
 294 
     | 
    
         
            +
                    tracks.push({
         
     | 
| 
      
 295 
     | 
    
         
            +
                      type: 'data'
         
     | 
| 
      
 296 
     | 
    
         
            +
                    });
         
     | 
| 
      
 297 
     | 
    
         
            +
                  }
         
     | 
| 
      
 298 
     | 
    
         
            +
                }
         
     | 
| 
      
 299 
     | 
    
         
            +
                // Done
         
     | 
| 
      
 300 
     | 
    
         
            +
                return tracks;
         
     | 
| 
      
 301 
     | 
    
         
            +
              };
         
     | 
| 
      
 302 
     | 
    
         
            +
             
     | 
| 
      
 303 
     | 
    
         
            +
              // Helper function to convert a track object to a set of constraints
         
     | 
| 
      
 304 
     | 
    
         
            +
              Janus.trackConstraints = function (track) {
         
     | 
| 
      
 305 
     | 
    
         
            +
                let constraints = {};
         
     | 
| 
      
 306 
     | 
    
         
            +
                if (!track || !track.capture) return constraints;
         
     | 
| 
      
 307 
     | 
    
         
            +
                if (track.type === 'audio') {
         
     | 
| 
      
 308 
     | 
    
         
            +
                  // Just put the capture part in the constraints
         
     | 
| 
      
 309 
     | 
    
         
            +
                  constraints.audio = track.capture;
         
     | 
| 
      
 310 
     | 
    
         
            +
                } else if (track.type === 'video') {
         
     | 
| 
      
 311 
     | 
    
         
            +
                  // Check if one of the keywords was passed
         
     | 
| 
      
 312 
     | 
    
         
            +
                  if ((track.simulcast || track.svc) && track.capture === true) track.capture = 'hires';
         
     | 
| 
      
 313 
     | 
    
         
            +
                  if (track.capture === true || typeof track.capture === 'object') {
         
     | 
| 
      
 314 
     | 
    
         
            +
                    // Use the provided capture object as video constraint
         
     | 
| 
      
 315 
     | 
    
         
            +
                    constraints.video = track.capture;
         
     | 
| 
      
 316 
     | 
    
         
            +
                  } else {
         
     | 
| 
      
 317 
     | 
    
         
            +
                    let width = 0;
         
     | 
| 
      
 318 
     | 
    
         
            +
                    let height = 0;
         
     | 
| 
      
 319 
     | 
    
         
            +
                    if (track.capture === 'lowres') {
         
     | 
| 
      
 320 
     | 
    
         
            +
                      // Small resolution, 4:3
         
     | 
| 
      
 321 
     | 
    
         
            +
                      width = 320;
         
     | 
| 
      
 322 
     | 
    
         
            +
                      height = 240;
         
     | 
| 
      
 323 
     | 
    
         
            +
                    } else if (track.capture === 'lowres-16:9') {
         
     | 
| 
      
 324 
     | 
    
         
            +
                      // Small resolution, 16:9
         
     | 
| 
      
 325 
     | 
    
         
            +
                      width = 320;
         
     | 
| 
      
 326 
     | 
    
         
            +
                      height = 180;
         
     | 
| 
      
 327 
     | 
    
         
            +
                    } else if (track.capture === 'hires' || track.capture === 'hires-16:9' || track.capture === 'hdres') {
         
     | 
| 
      
 328 
     | 
    
         
            +
                      // High(HD) resolution is only 16:9
         
     | 
| 
      
 329 
     | 
    
         
            +
                      width = 1280;
         
     | 
| 
      
 330 
     | 
    
         
            +
                      height = 720;
         
     | 
| 
      
 331 
     | 
    
         
            +
                    } else if (track.capture === 'fhdres') {
         
     | 
| 
      
 332 
     | 
    
         
            +
                      // Full HD resolution is only 16:9
         
     | 
| 
      
 333 
     | 
    
         
            +
                      width = 1920;
         
     | 
| 
      
 334 
     | 
    
         
            +
                      height = 1080;
         
     | 
| 
      
 335 
     | 
    
         
            +
                    } else if (track.capture === '4kres') {
         
     | 
| 
      
 336 
     | 
    
         
            +
                      // 4K resolution is only 16:9
         
     | 
| 
      
 337 
     | 
    
         
            +
                      width = 3840;
         
     | 
| 
      
 338 
     | 
    
         
            +
                      height = 2160;
         
     | 
| 
      
 339 
     | 
    
         
            +
                    } else if (track.capture === 'stdres') {
         
     | 
| 
      
 340 
     | 
    
         
            +
                      // Normal resolution, 4:3
         
     | 
| 
      
 341 
     | 
    
         
            +
                      width = 640;
         
     | 
| 
      
 342 
     | 
    
         
            +
                      height = 480;
         
     | 
| 
      
 343 
     | 
    
         
            +
                    } else if (track.capture === 'stdres-16:9') {
         
     | 
| 
      
 344 
     | 
    
         
            +
                      // Normal resolution, 16:9
         
     | 
| 
      
 345 
     | 
    
         
            +
                      width = 640;
         
     | 
| 
      
 346 
     | 
    
         
            +
                      height = 360;
         
     | 
| 
      
 347 
     | 
    
         
            +
                    } else {
         
     | 
| 
      
 348 
     | 
    
         
            +
                      Janus.log('Default video setting is stdres 4:3');
         
     | 
| 
      
 349 
     | 
    
         
            +
                      width = 640;
         
     | 
| 
      
 350 
     | 
    
         
            +
                      height = 480;
         
     | 
| 
      
 351 
     | 
    
         
            +
                    }
         
     | 
| 
      
 352 
     | 
    
         
            +
                    constraints.video = {
         
     | 
| 
      
 353 
     | 
    
         
            +
                      width: {
         
     | 
| 
      
 354 
     | 
    
         
            +
                        ideal: width
         
     | 
| 
      
 355 
     | 
    
         
            +
                      },
         
     | 
| 
      
 356 
     | 
    
         
            +
                      height: {
         
     | 
| 
      
 357 
     | 
    
         
            +
                        ideal: height
         
     | 
| 
      
 358 
     | 
    
         
            +
                      }
         
     | 
| 
      
 359 
     | 
    
         
            +
                    };
         
     | 
| 
      
 360 
     | 
    
         
            +
                  }
         
     | 
| 
      
 361 
     | 
    
         
            +
                } else if (track.type === 'screen') {
         
     | 
| 
      
 362 
     | 
    
         
            +
                  // Use the provided capture object as video constraint
         
     | 
| 
      
 363 
     | 
    
         
            +
                  constraints.video = track.capture;
         
     | 
| 
      
 364 
     | 
    
         
            +
                }
         
     | 
| 
      
 365 
     | 
    
         
            +
                return constraints;
         
     | 
| 
      
 366 
     | 
    
         
            +
              };
         
     | 
| 
      
 367 
     | 
    
         
            +
              Janus.noop = function () {};
         
     | 
| 
      
 368 
     | 
    
         
            +
              Janus.dataChanDefaultLabel = "JanusDataChannel";
         
     | 
| 
      
 369 
     | 
    
         
            +
             
     | 
| 
      
 370 
     | 
    
         
            +
              // Note: in the future we may want to change this, e.g., as was
         
     | 
| 
      
 371 
     | 
    
         
            +
              // attempted in https://github.com/meetecho/janus-gateway/issues/1670
         
     | 
| 
      
 372 
     | 
    
         
            +
              Janus.endOfCandidates = null;
         
     | 
| 
      
 373 
     | 
    
         
            +
             
     | 
| 
      
 374 
     | 
    
         
            +
              // Stop all tracks from a given stream
         
     | 
| 
      
 375 
     | 
    
         
            +
              Janus.stopAllTracks = function (stream) {
         
     | 
| 
      
 376 
     | 
    
         
            +
                try {
         
     | 
| 
      
 377 
     | 
    
         
            +
                  // Try a MediaStreamTrack.stop() for each track
         
     | 
| 
      
 378 
     | 
    
         
            +
                  let tracks = stream.getTracks();
         
     | 
| 
      
 379 
     | 
    
         
            +
                  for (let mst of tracks) {
         
     | 
| 
      
 380 
     | 
    
         
            +
                    Janus.log(mst);
         
     | 
| 
      
 381 
     | 
    
         
            +
                    if (mst && mst.dontStop !== true) {
         
     | 
| 
      
 382 
     | 
    
         
            +
                      mst.stop();
         
     | 
| 
      
 383 
     | 
    
         
            +
                    }
         
     | 
| 
      
 384 
     | 
    
         
            +
                  }
         
     | 
| 
      
 385 
     | 
    
         
            +
                  // eslint-disable-next-line no-unused-vars
         
     | 
| 
      
 386 
     | 
    
         
            +
                } catch (e) {
         
     | 
| 
      
 387 
     | 
    
         
            +
                  // Do nothing if this fails
         
     | 
| 
      
 388 
     | 
    
         
            +
                }
         
     | 
| 
      
 389 
     | 
    
         
            +
              };
         
     | 
| 
      
 390 
     | 
    
         
            +
             
     | 
| 
      
 391 
     | 
    
         
            +
              // Initialization
         
     | 
| 
      
 392 
     | 
    
         
            +
              Janus.init = function (options) {
         
     | 
| 
      
 393 
     | 
    
         
            +
                options = options || {};
         
     | 
| 
      
 394 
     | 
    
         
            +
                options.callback = typeof options.callback == "function" ? options.callback : Janus.noop;
         
     | 
| 
      
 395 
     | 
    
         
            +
                if (Janus.initDone) {
         
     | 
| 
      
 396 
     | 
    
         
            +
                  // Already initialized
         
     | 
| 
      
 397 
     | 
    
         
            +
                  options.callback();
         
     | 
| 
      
 398 
     | 
    
         
            +
                } else {
         
     | 
| 
      
 399 
     | 
    
         
            +
                  if (typeof console.log == "undefined") {
         
     | 
| 
      
 400 
     | 
    
         
            +
                    console.log = function () {};
         
     | 
| 
      
 401 
     | 
    
         
            +
                  }
         
     | 
| 
      
 402 
     | 
    
         
            +
                  // Console logging (all debugging disabled by default)
         
     | 
| 
      
 403 
     | 
    
         
            +
                  Janus.trace = Janus.noop;
         
     | 
| 
      
 404 
     | 
    
         
            +
                  Janus.debug = Janus.noop;
         
     | 
| 
      
 405 
     | 
    
         
            +
                  Janus.vdebug = Janus.noop;
         
     | 
| 
      
 406 
     | 
    
         
            +
                  Janus.log = Janus.noop;
         
     | 
| 
      
 407 
     | 
    
         
            +
                  Janus.warn = Janus.noop;
         
     | 
| 
      
 408 
     | 
    
         
            +
                  Janus.error = Janus.noop;
         
     | 
| 
      
 409 
     | 
    
         
            +
                  if (options.debug === true || options.debug === "all") {
         
     | 
| 
      
 410 
     | 
    
         
            +
                    // Enable all debugging levels
         
     | 
| 
      
 411 
     | 
    
         
            +
                    Janus.trace = console.trace.bind(console);
         
     | 
| 
      
 412 
     | 
    
         
            +
                    Janus.debug = console.debug.bind(console);
         
     | 
| 
      
 413 
     | 
    
         
            +
                    Janus.vdebug = console.debug.bind(console);
         
     | 
| 
      
 414 
     | 
    
         
            +
                    Janus.log = console.log.bind(console);
         
     | 
| 
      
 415 
     | 
    
         
            +
                    Janus.warn = console.warn.bind(console);
         
     | 
| 
      
 416 
     | 
    
         
            +
                    Janus.error = console.error.bind(console);
         
     | 
| 
      
 417 
     | 
    
         
            +
                  } else if (Array.isArray(options.debug)) {
         
     | 
| 
      
 418 
     | 
    
         
            +
                    for (let d of options.debug) {
         
     | 
| 
      
 419 
     | 
    
         
            +
                      switch (d) {
         
     | 
| 
      
 420 
     | 
    
         
            +
                        case "trace":
         
     | 
| 
      
 421 
     | 
    
         
            +
                          Janus.trace = console.trace.bind(console);
         
     | 
| 
      
 422 
     | 
    
         
            +
                          break;
         
     | 
| 
      
 423 
     | 
    
         
            +
                        case "debug":
         
     | 
| 
      
 424 
     | 
    
         
            +
                          Janus.debug = console.debug.bind(console);
         
     | 
| 
      
 425 
     | 
    
         
            +
                          break;
         
     | 
| 
      
 426 
     | 
    
         
            +
                        case "vdebug":
         
     | 
| 
      
 427 
     | 
    
         
            +
                          Janus.vdebug = console.debug.bind(console);
         
     | 
| 
      
 428 
     | 
    
         
            +
                          break;
         
     | 
| 
      
 429 
     | 
    
         
            +
                        case "log":
         
     | 
| 
      
 430 
     | 
    
         
            +
                          Janus.log = console.log.bind(console);
         
     | 
| 
      
 431 
     | 
    
         
            +
                          break;
         
     | 
| 
      
 432 
     | 
    
         
            +
                        case "warn":
         
     | 
| 
      
 433 
     | 
    
         
            +
                          Janus.warn = console.warn.bind(console);
         
     | 
| 
      
 434 
     | 
    
         
            +
                          break;
         
     | 
| 
      
 435 
     | 
    
         
            +
                        case "error":
         
     | 
| 
      
 436 
     | 
    
         
            +
                          Janus.error = console.error.bind(console);
         
     | 
| 
      
 437 
     | 
    
         
            +
                          break;
         
     | 
| 
      
 438 
     | 
    
         
            +
                      }
         
     | 
| 
      
 439 
     | 
    
         
            +
                    }
         
     | 
| 
      
 440 
     | 
    
         
            +
                  }
         
     | 
| 
      
 441 
     | 
    
         
            +
                  Janus.log("Initializing library");
         
     | 
| 
      
 442 
     | 
    
         
            +
                  let usedDependencies = options.dependencies || Janus.useDefaultDependencies();
         
     | 
| 
      
 443 
     | 
    
         
            +
                  Janus.isArray = usedDependencies.isArray;
         
     | 
| 
      
 444 
     | 
    
         
            +
                  Janus.webRTCAdapter = usedDependencies.webRTCAdapter;
         
     | 
| 
      
 445 
     | 
    
         
            +
                  Janus.httpAPICall = usedDependencies.httpAPICall;
         
     | 
| 
      
 446 
     | 
    
         
            +
                  Janus.newWebSocket = usedDependencies.newWebSocket;
         
     | 
| 
      
 447 
     | 
    
         
            +
                  Janus.extension = usedDependencies.extension;
         
     | 
| 
      
 448 
     | 
    
         
            +
                  Janus.extension.init();
         
     | 
| 
      
 449 
     | 
    
         
            +
             
     | 
| 
      
 450 
     | 
    
         
            +
                  // Helper method to enumerate devices
         
     | 
| 
      
 451 
     | 
    
         
            +
                  Janus.listDevices = function (callback, config) {
         
     | 
| 
      
 452 
     | 
    
         
            +
                    callback = typeof callback == "function" ? callback : Janus.noop;
         
     | 
| 
      
 453 
     | 
    
         
            +
                    if (!config) config = {
         
     | 
| 
      
 454 
     | 
    
         
            +
                      audio: true,
         
     | 
| 
      
 455 
     | 
    
         
            +
                      video: true
         
     | 
| 
      
 456 
     | 
    
         
            +
                    };
         
     | 
| 
      
 457 
     | 
    
         
            +
                    if (Janus.isGetUserMediaAvailable()) {
         
     | 
| 
      
 458 
     | 
    
         
            +
                      navigator.mediaDevices.getUserMedia(config).then(function (stream) {
         
     | 
| 
      
 459 
     | 
    
         
            +
                        navigator.mediaDevices.enumerateDevices().then(function (devices) {
         
     | 
| 
      
 460 
     | 
    
         
            +
                          Janus.debug(devices);
         
     | 
| 
      
 461 
     | 
    
         
            +
                          callback(devices);
         
     | 
| 
      
 462 
     | 
    
         
            +
                          // Get rid of the now useless stream
         
     | 
| 
      
 463 
     | 
    
         
            +
                          Janus.stopAllTracks(stream);
         
     | 
| 
      
 464 
     | 
    
         
            +
                        });
         
     | 
| 
      
 465 
     | 
    
         
            +
                      }).catch(function (err) {
         
     | 
| 
      
 466 
     | 
    
         
            +
                        Janus.error(err);
         
     | 
| 
      
 467 
     | 
    
         
            +
                        callback([]);
         
     | 
| 
      
 468 
     | 
    
         
            +
                      });
         
     | 
| 
      
 469 
     | 
    
         
            +
                    } else {
         
     | 
| 
      
 470 
     | 
    
         
            +
                      Janus.warn("navigator.mediaDevices unavailable");
         
     | 
| 
      
 471 
     | 
    
         
            +
                      callback([]);
         
     | 
| 
      
 472 
     | 
    
         
            +
                    }
         
     | 
| 
      
 473 
     | 
    
         
            +
                  };
         
     | 
| 
      
 474 
     | 
    
         
            +
                  // Helper methods to attach/reattach a stream to a video element (previously part of adapter.js)
         
     | 
| 
      
 475 
     | 
    
         
            +
                  Janus.attachMediaStream = function (element, stream) {
         
     | 
| 
      
 476 
     | 
    
         
            +
                    try {
         
     | 
| 
      
 477 
     | 
    
         
            +
                      element.srcObject = stream;
         
     | 
| 
      
 478 
     | 
    
         
            +
                      // eslint-disable-next-line no-unused-vars
         
     | 
| 
      
 479 
     | 
    
         
            +
                    } catch (e) {
         
     | 
| 
      
 480 
     | 
    
         
            +
                      try {
         
     | 
| 
      
 481 
     | 
    
         
            +
                        element.src = URL.createObjectURL(stream);
         
     | 
| 
      
 482 
     | 
    
         
            +
                      } catch (e) {
         
     | 
| 
      
 483 
     | 
    
         
            +
                        Janus.error("Error attaching stream to element", e);
         
     | 
| 
      
 484 
     | 
    
         
            +
                      }
         
     | 
| 
      
 485 
     | 
    
         
            +
                    }
         
     | 
| 
      
 486 
     | 
    
         
            +
                  };
         
     | 
| 
      
 487 
     | 
    
         
            +
                  Janus.reattachMediaStream = function (to, from) {
         
     | 
| 
      
 488 
     | 
    
         
            +
                    try {
         
     | 
| 
      
 489 
     | 
    
         
            +
                      to.srcObject = from.srcObject;
         
     | 
| 
      
 490 
     | 
    
         
            +
                      // eslint-disable-next-line no-unused-vars
         
     | 
| 
      
 491 
     | 
    
         
            +
                    } catch (e) {
         
     | 
| 
      
 492 
     | 
    
         
            +
                      try {
         
     | 
| 
      
 493 
     | 
    
         
            +
                        to.src = from.src;
         
     | 
| 
      
 494 
     | 
    
         
            +
                      } catch (e) {
         
     | 
| 
      
 495 
     | 
    
         
            +
                        Janus.error("Error reattaching stream to element", e);
         
     | 
| 
      
 496 
     | 
    
         
            +
                      }
         
     | 
| 
      
 497 
     | 
    
         
            +
                    }
         
     | 
| 
      
 498 
     | 
    
         
            +
                  };
         
     | 
| 
      
 499 
     | 
    
         
            +
                  // Detect tab close: make sure we don't loose existing onbeforeunload handlers
         
     | 
| 
      
 500 
     | 
    
         
            +
                  // (note: for iOS we need to subscribe to a different event, 'pagehide', see
         
     | 
| 
      
 501 
     | 
    
         
            +
                  // https://gist.github.com/thehunmonkgroup/6bee8941a49b86be31a787fe8f4b8cfe)
         
     | 
| 
      
 502 
     | 
    
         
            +
                  let iOS = ['iPad', 'iPhone', 'iPod'].indexOf(navigator.platform) >= 0;
         
     | 
| 
      
 503 
     | 
    
         
            +
                  let eventName = iOS ? 'pagehide' : 'beforeunload';
         
     | 
| 
      
 504 
     | 
    
         
            +
                  let oldOBF = window["on" + eventName];
         
     | 
| 
      
 505 
     | 
    
         
            +
                  window.addEventListener(eventName, function () {
         
     | 
| 
      
 506 
     | 
    
         
            +
                    Janus.log("Closing window");
         
     | 
| 
      
 507 
     | 
    
         
            +
                    for (const [sessionId, session] of Janus.sessions) {
         
     | 
| 
      
 508 
     | 
    
         
            +
                      if (session && session.destroyOnUnload) {
         
     | 
| 
      
 509 
     | 
    
         
            +
                        Janus.log("Destroying session " + sessionId);
         
     | 
| 
      
 510 
     | 
    
         
            +
                        session.destroy({
         
     | 
| 
      
 511 
     | 
    
         
            +
                          unload: true,
         
     | 
| 
      
 512 
     | 
    
         
            +
                          notifyDestroyed: false
         
     | 
| 
      
 513 
     | 
    
         
            +
                        });
         
     | 
| 
      
 514 
     | 
    
         
            +
                      }
         
     | 
| 
      
 515 
     | 
    
         
            +
                    }
         
     | 
| 
      
 516 
     | 
    
         
            +
                    if (oldOBF && typeof oldOBF == "function") {
         
     | 
| 
      
 517 
     | 
    
         
            +
                      oldOBF();
         
     | 
| 
      
 518 
     | 
    
         
            +
                    }
         
     | 
| 
      
 519 
     | 
    
         
            +
                  });
         
     | 
| 
      
 520 
     | 
    
         
            +
                  // If this is a Safari, check if VP8 or VP9 are supported
         
     | 
| 
      
 521 
     | 
    
         
            +
                  Janus.safariVp8 = false;
         
     | 
| 
      
 522 
     | 
    
         
            +
                  Janus.safariVp9 = false;
         
     | 
| 
      
 523 
     | 
    
         
            +
                  if (Janus.webRTCAdapter.browserDetails.browser === 'safari' && Janus.webRTCAdapter.browserDetails.version >= 605) {
         
     | 
| 
      
 524 
     | 
    
         
            +
                    // Let's see if RTCRtpSender.getCapabilities() is there
         
     | 
| 
      
 525 
     | 
    
         
            +
                    if (RTCRtpSender && RTCRtpSender.getCapabilities && RTCRtpSender.getCapabilities("video") && RTCRtpSender.getCapabilities("video").codecs && RTCRtpSender.getCapabilities("video").codecs.length) {
         
     | 
| 
      
 526 
     | 
    
         
            +
                      for (let codec of RTCRtpSender.getCapabilities("video").codecs) {
         
     | 
| 
      
 527 
     | 
    
         
            +
                        if (codec && codec.mimeType && codec.mimeType.toLowerCase() === "video/vp8") {
         
     | 
| 
      
 528 
     | 
    
         
            +
                          Janus.safariVp8 = true;
         
     | 
| 
      
 529 
     | 
    
         
            +
                        } else if (codec && codec.mimeType && codec.mimeType.toLowerCase() === "video/vp9") {
         
     | 
| 
      
 530 
     | 
    
         
            +
                          Janus.safariVp9 = true;
         
     | 
| 
      
 531 
     | 
    
         
            +
                        }
         
     | 
| 
      
 532 
     | 
    
         
            +
                      }
         
     | 
| 
      
 533 
     | 
    
         
            +
                      if (Janus.safariVp8) {
         
     | 
| 
      
 534 
     | 
    
         
            +
                        Janus.log("This version of Safari supports VP8");
         
     | 
| 
      
 535 
     | 
    
         
            +
                      } else {
         
     | 
| 
      
 536 
     | 
    
         
            +
                        Janus.warn("This version of Safari does NOT support VP8: if you're using a Technology Preview, " + "try enabling the 'WebRTC VP8 codec' setting in the 'Experimental Features' Develop menu");
         
     | 
| 
      
 537 
     | 
    
         
            +
                      }
         
     | 
| 
      
 538 
     | 
    
         
            +
                    } else {
         
     | 
| 
      
 539 
     | 
    
         
            +
                      // We do it in a very ugly way, as there's no alternative...
         
     | 
| 
      
 540 
     | 
    
         
            +
                      // We create a PeerConnection to see if VP8 is in an offer
         
     | 
| 
      
 541 
     | 
    
         
            +
                      let testpc = new RTCPeerConnection({});
         
     | 
| 
      
 542 
     | 
    
         
            +
                      testpc.createOffer({
         
     | 
| 
      
 543 
     | 
    
         
            +
                        offerToReceiveVideo: true
         
     | 
| 
      
 544 
     | 
    
         
            +
                      }).then(function (offer) {
         
     | 
| 
      
 545 
     | 
    
         
            +
                        Janus.safariVp8 = offer.sdp.indexOf("VP8") !== -1;
         
     | 
| 
      
 546 
     | 
    
         
            +
                        Janus.safariVp9 = offer.sdp.indexOf("VP9") !== -1;
         
     | 
| 
      
 547 
     | 
    
         
            +
                        if (Janus.safariVp8) {
         
     | 
| 
      
 548 
     | 
    
         
            +
                          Janus.log("This version of Safari supports VP8");
         
     | 
| 
      
 549 
     | 
    
         
            +
                        } else {
         
     | 
| 
      
 550 
     | 
    
         
            +
                          Janus.warn("This version of Safari does NOT support VP8: if you're using a Technology Preview, " + "try enabling the 'WebRTC VP8 codec' setting in the 'Experimental Features' Develop menu");
         
     | 
| 
      
 551 
     | 
    
         
            +
                        }
         
     | 
| 
      
 552 
     | 
    
         
            +
                        testpc.close();
         
     | 
| 
      
 553 
     | 
    
         
            +
                        testpc = null;
         
     | 
| 
      
 554 
     | 
    
         
            +
                      });
         
     | 
| 
      
 555 
     | 
    
         
            +
                    }
         
     | 
| 
      
 556 
     | 
    
         
            +
                  }
         
     | 
| 
      
 557 
     | 
    
         
            +
                  Janus.initDone = true;
         
     | 
| 
      
 558 
     | 
    
         
            +
                  options.callback();
         
     | 
| 
      
 559 
     | 
    
         
            +
                }
         
     | 
| 
      
 560 
     | 
    
         
            +
              };
         
     | 
| 
      
 561 
     | 
    
         
            +
             
     | 
| 
      
 562 
     | 
    
         
            +
              // Helper method to check whether WebRTC is supported by this browser
         
     | 
| 
      
 563 
     | 
    
         
            +
              Janus.isWebrtcSupported = function () {
         
     | 
| 
      
 564 
     | 
    
         
            +
                return !!window.RTCPeerConnection;
         
     | 
| 
      
 565 
     | 
    
         
            +
              };
         
     | 
| 
      
 566 
     | 
    
         
            +
              // Helper method to check whether devices can be accessed by this browser (e.g., not possible via plain HTTP)
         
     | 
| 
      
 567 
     | 
    
         
            +
              Janus.isGetUserMediaAvailable = function () {
         
     | 
| 
      
 568 
     | 
    
         
            +
                return navigator.mediaDevices && navigator.mediaDevices.getUserMedia;
         
     | 
| 
      
 569 
     | 
    
         
            +
              };
         
     | 
| 
      
 570 
     | 
    
         
            +
             
     | 
| 
      
 571 
     | 
    
         
            +
              // Helper method to create random identifiers (e.g., transaction)
         
     | 
| 
      
 572 
     | 
    
         
            +
              Janus.randomString = function (len) {
         
     | 
| 
      
 573 
     | 
    
         
            +
                let charSet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
         
     | 
| 
      
 574 
     | 
    
         
            +
                let randomString = '';
         
     | 
| 
      
 575 
     | 
    
         
            +
                for (let i = 0; i < len; i++) {
         
     | 
| 
      
 576 
     | 
    
         
            +
                  let randomPoz = Math.floor(Math.random() * charSet.length);
         
     | 
| 
      
 577 
     | 
    
         
            +
                  randomString += charSet.charAt(randomPoz);
         
     | 
| 
      
 578 
     | 
    
         
            +
                }
         
     | 
| 
      
 579 
     | 
    
         
            +
                return randomString;
         
     | 
| 
      
 580 
     | 
    
         
            +
              };
         
     | 
| 
      
 581 
     | 
    
         
            +
              function Janus(gatewayCallbacks) {
         
     | 
| 
      
 582 
     | 
    
         
            +
                gatewayCallbacks = gatewayCallbacks || {};
         
     | 
| 
      
 583 
     | 
    
         
            +
                gatewayCallbacks.success = typeof gatewayCallbacks.success == "function" ? gatewayCallbacks.success : Janus.noop;
         
     | 
| 
      
 584 
     | 
    
         
            +
                gatewayCallbacks.error = typeof gatewayCallbacks.error == "function" ? gatewayCallbacks.error : Janus.noop;
         
     | 
| 
      
 585 
     | 
    
         
            +
                gatewayCallbacks.destroyed = typeof gatewayCallbacks.destroyed == "function" ? gatewayCallbacks.destroyed : Janus.noop;
         
     | 
| 
      
 586 
     | 
    
         
            +
                if (!Janus.initDone) {
         
     | 
| 
      
 587 
     | 
    
         
            +
                  gatewayCallbacks.error("Library not initialized");
         
     | 
| 
      
 588 
     | 
    
         
            +
                  return {};
         
     | 
| 
      
 589 
     | 
    
         
            +
                }
         
     | 
| 
      
 590 
     | 
    
         
            +
                if (!Janus.isWebrtcSupported()) {
         
     | 
| 
      
 591 
     | 
    
         
            +
                  gatewayCallbacks.error("WebRTC not supported by this browser");
         
     | 
| 
      
 592 
     | 
    
         
            +
                  return {};
         
     | 
| 
      
 593 
     | 
    
         
            +
                }
         
     | 
| 
      
 594 
     | 
    
         
            +
                Janus.log("Library initialized: " + Janus.initDone);
         
     | 
| 
      
 595 
     | 
    
         
            +
                if (!gatewayCallbacks.server) {
         
     | 
| 
      
 596 
     | 
    
         
            +
                  gatewayCallbacks.error("Invalid server url");
         
     | 
| 
      
 597 
     | 
    
         
            +
                  return {};
         
     | 
| 
      
 598 
     | 
    
         
            +
                }
         
     | 
| 
      
 599 
     | 
    
         
            +
                let websockets = false;
         
     | 
| 
      
 600 
     | 
    
         
            +
                let ws = null;
         
     | 
| 
      
 601 
     | 
    
         
            +
                let wsHandlers = {};
         
     | 
| 
      
 602 
     | 
    
         
            +
                let wsKeepaliveTimeoutId = null;
         
     | 
| 
      
 603 
     | 
    
         
            +
                let servers = null;
         
     | 
| 
      
 604 
     | 
    
         
            +
                let serversIndex = 0;
         
     | 
| 
      
 605 
     | 
    
         
            +
                let server = gatewayCallbacks.server;
         
     | 
| 
      
 606 
     | 
    
         
            +
                if (Janus.isArray(server)) {
         
     | 
| 
      
 607 
     | 
    
         
            +
                  Janus.log("Multiple servers provided (" + server.length + "), will use the first that works");
         
     | 
| 
      
 608 
     | 
    
         
            +
                  server = null;
         
     | 
| 
      
 609 
     | 
    
         
            +
                  servers = gatewayCallbacks.server;
         
     | 
| 
      
 610 
     | 
    
         
            +
                  Janus.debug(servers);
         
     | 
| 
      
 611 
     | 
    
         
            +
                } else {
         
     | 
| 
      
 612 
     | 
    
         
            +
                  if (server.indexOf("ws") === 0) {
         
     | 
| 
      
 613 
     | 
    
         
            +
                    websockets = true;
         
     | 
| 
      
 614 
     | 
    
         
            +
                    Janus.log("Using WebSockets to contact Janus: " + server);
         
     | 
| 
      
 615 
     | 
    
         
            +
                  } else {
         
     | 
| 
      
 616 
     | 
    
         
            +
                    websockets = false;
         
     | 
| 
      
 617 
     | 
    
         
            +
                    Janus.log("Using REST API to contact Janus: " + server);
         
     | 
| 
      
 618 
     | 
    
         
            +
                  }
         
     | 
| 
      
 619 
     | 
    
         
            +
                }
         
     | 
| 
      
 620 
     | 
    
         
            +
                let iceServers = gatewayCallbacks.iceServers || [{
         
     | 
| 
      
 621 
     | 
    
         
            +
                  urls: "stun:stun.l.google.com:19302"
         
     | 
| 
      
 622 
     | 
    
         
            +
                }];
         
     | 
| 
      
 623 
     | 
    
         
            +
                let iceTransportPolicy = gatewayCallbacks.iceTransportPolicy;
         
     | 
| 
      
 624 
     | 
    
         
            +
                let bundlePolicy = gatewayCallbacks.bundlePolicy;
         
     | 
| 
      
 625 
     | 
    
         
            +
                // Whether we should enable the withCredentials flag for XHR requests
         
     | 
| 
      
 626 
     | 
    
         
            +
                let withCredentials = false;
         
     | 
| 
      
 627 
     | 
    
         
            +
                if (typeof gatewayCallbacks.withCredentials !== 'undefined' && gatewayCallbacks.withCredentials !== null) withCredentials = gatewayCallbacks.withCredentials === true;
         
     | 
| 
      
 628 
     | 
    
         
            +
                // Optional max events
         
     | 
| 
      
 629 
     | 
    
         
            +
                let maxev = 10;
         
     | 
| 
      
 630 
     | 
    
         
            +
                if (typeof gatewayCallbacks.max_poll_events !== 'undefined' && gatewayCallbacks.max_poll_events !== null) maxev = gatewayCallbacks.max_poll_events;
         
     | 
| 
      
 631 
     | 
    
         
            +
                if (maxev < 1) maxev = 1;
         
     | 
| 
      
 632 
     | 
    
         
            +
                // Token to use (only if the token based authentication mechanism is enabled)
         
     | 
| 
      
 633 
     | 
    
         
            +
                let token = null;
         
     | 
| 
      
 634 
     | 
    
         
            +
                if (typeof gatewayCallbacks.token !== 'undefined' && gatewayCallbacks.token !== null) token = gatewayCallbacks.token;
         
     | 
| 
      
 635 
     | 
    
         
            +
                // API secret to use (only if the shared API secret is enabled)
         
     | 
| 
      
 636 
     | 
    
         
            +
                let apisecret = null;
         
     | 
| 
      
 637 
     | 
    
         
            +
                if (typeof gatewayCallbacks.apisecret !== 'undefined' && gatewayCallbacks.apisecret !== null) apisecret = gatewayCallbacks.apisecret;
         
     | 
| 
      
 638 
     | 
    
         
            +
                // Whether we should destroy this session when onbeforeunload is called
         
     | 
| 
      
 639 
     | 
    
         
            +
                this.destroyOnUnload = true;
         
     | 
| 
      
 640 
     | 
    
         
            +
                if (typeof gatewayCallbacks.destroyOnUnload !== 'undefined' && gatewayCallbacks.destroyOnUnload !== null) this.destroyOnUnload = gatewayCallbacks.destroyOnUnload === true;
         
     | 
| 
      
 641 
     | 
    
         
            +
                // Some timeout-related values
         
     | 
| 
      
 642 
     | 
    
         
            +
                let keepAlivePeriod = 25000;
         
     | 
| 
      
 643 
     | 
    
         
            +
                if (typeof gatewayCallbacks.keepAlivePeriod !== 'undefined' && gatewayCallbacks.keepAlivePeriod !== null) keepAlivePeriod = gatewayCallbacks.keepAlivePeriod;
         
     | 
| 
      
 644 
     | 
    
         
            +
                if (isNaN(keepAlivePeriod)) keepAlivePeriod = 25000;
         
     | 
| 
      
 645 
     | 
    
         
            +
                let longPollTimeout = 60000;
         
     | 
| 
      
 646 
     | 
    
         
            +
                if (typeof gatewayCallbacks.longPollTimeout !== 'undefined' && gatewayCallbacks.longPollTimeout !== null) longPollTimeout = gatewayCallbacks.longPollTimeout;
         
     | 
| 
      
 647 
     | 
    
         
            +
                if (isNaN(longPollTimeout)) longPollTimeout = 60000;
         
     | 
| 
      
 648 
     | 
    
         
            +
             
     | 
| 
      
 649 
     | 
    
         
            +
                // overrides for default maxBitrate values for simulcasting
         
     | 
| 
      
 650 
     | 
    
         
            +
                function getMaxBitrates(simulcastMaxBitrates) {
         
     | 
| 
      
 651 
     | 
    
         
            +
                  let maxBitrates = {
         
     | 
| 
      
 652 
     | 
    
         
            +
                    high: 900000,
         
     | 
| 
      
 653 
     | 
    
         
            +
                    medium: 300000,
         
     | 
| 
      
 654 
     | 
    
         
            +
                    low: 100000
         
     | 
| 
      
 655 
     | 
    
         
            +
                  };
         
     | 
| 
      
 656 
     | 
    
         
            +
                  if (typeof simulcastMaxBitrates !== 'undefined' && simulcastMaxBitrates !== null) {
         
     | 
| 
      
 657 
     | 
    
         
            +
                    if (simulcastMaxBitrates.high) maxBitrates.high = simulcastMaxBitrates.high;
         
     | 
| 
      
 658 
     | 
    
         
            +
                    if (simulcastMaxBitrates.medium) maxBitrates.medium = simulcastMaxBitrates.medium;
         
     | 
| 
      
 659 
     | 
    
         
            +
                    if (simulcastMaxBitrates.low) maxBitrates.low = simulcastMaxBitrates.low;
         
     | 
| 
      
 660 
     | 
    
         
            +
                  }
         
     | 
| 
      
 661 
     | 
    
         
            +
                  return maxBitrates;
         
     | 
| 
      
 662 
     | 
    
         
            +
                }
         
     | 
| 
      
 663 
     | 
    
         
            +
                let connected = false;
         
     | 
| 
      
 664 
     | 
    
         
            +
                let sessionId = null;
         
     | 
| 
      
 665 
     | 
    
         
            +
                let pluginHandles = new Map();
         
     | 
| 
      
 666 
     | 
    
         
            +
                let that = this;
         
     | 
| 
      
 667 
     | 
    
         
            +
                let retries = 0;
         
     | 
| 
      
 668 
     | 
    
         
            +
                let transactions = new Map();
         
     | 
| 
      
 669 
     | 
    
         
            +
                createSession(gatewayCallbacks);
         
     | 
| 
      
 670 
     | 
    
         
            +
             
     | 
| 
      
 671 
     | 
    
         
            +
                // Public methods
         
     | 
| 
      
 672 
     | 
    
         
            +
                this.getServer = function () {
         
     | 
| 
      
 673 
     | 
    
         
            +
                  return server;
         
     | 
| 
      
 674 
     | 
    
         
            +
                };
         
     | 
| 
      
 675 
     | 
    
         
            +
                this.isConnected = function () {
         
     | 
| 
      
 676 
     | 
    
         
            +
                  return connected;
         
     | 
| 
      
 677 
     | 
    
         
            +
                };
         
     | 
| 
      
 678 
     | 
    
         
            +
                this.reconnect = function (callbacks) {
         
     | 
| 
      
 679 
     | 
    
         
            +
                  callbacks = callbacks || {};
         
     | 
| 
      
 680 
     | 
    
         
            +
                  callbacks.success = typeof callbacks.success == "function" ? callbacks.success : Janus.noop;
         
     | 
| 
      
 681 
     | 
    
         
            +
                  callbacks.error = typeof callbacks.error == "function" ? callbacks.error : Janus.noop;
         
     | 
| 
      
 682 
     | 
    
         
            +
                  callbacks["reconnect"] = true;
         
     | 
| 
      
 683 
     | 
    
         
            +
                  createSession(callbacks);
         
     | 
| 
      
 684 
     | 
    
         
            +
                };
         
     | 
| 
      
 685 
     | 
    
         
            +
                this.getSessionId = function () {
         
     | 
| 
      
 686 
     | 
    
         
            +
                  return sessionId;
         
     | 
| 
      
 687 
     | 
    
         
            +
                };
         
     | 
| 
      
 688 
     | 
    
         
            +
                this.getInfo = function (callbacks) {
         
     | 
| 
      
 689 
     | 
    
         
            +
                  getInfo(callbacks);
         
     | 
| 
      
 690 
     | 
    
         
            +
                };
         
     | 
| 
      
 691 
     | 
    
         
            +
                this.destroy = function (callbacks) {
         
     | 
| 
      
 692 
     | 
    
         
            +
                  destroySession(callbacks);
         
     | 
| 
      
 693 
     | 
    
         
            +
                };
         
     | 
| 
      
 694 
     | 
    
         
            +
                this.attach = function (callbacks) {
         
     | 
| 
      
 695 
     | 
    
         
            +
                  createHandle(callbacks);
         
     | 
| 
      
 696 
     | 
    
         
            +
                };
         
     | 
| 
      
 697 
     | 
    
         
            +
                function eventHandler() {
         
     | 
| 
      
 698 
     | 
    
         
            +
                  if (sessionId == null) return;
         
     | 
| 
      
 699 
     | 
    
         
            +
                  Janus.debug('Long poll...');
         
     | 
| 
      
 700 
     | 
    
         
            +
                  if (!connected) {
         
     | 
| 
      
 701 
     | 
    
         
            +
                    Janus.warn("Is the server down? (connected=false)");
         
     | 
| 
      
 702 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 703 
     | 
    
         
            +
                  }
         
     | 
| 
      
 704 
     | 
    
         
            +
                  let longpoll = server + "/" + sessionId + "?rid=" + new Date().getTime();
         
     | 
| 
      
 705 
     | 
    
         
            +
                  if (maxev) longpoll = longpoll + "&maxev=" + maxev;
         
     | 
| 
      
 706 
     | 
    
         
            +
                  if (token) longpoll = longpoll + "&token=" + encodeURIComponent(token);
         
     | 
| 
      
 707 
     | 
    
         
            +
                  if (apisecret) longpoll = longpoll + "&apisecret=" + encodeURIComponent(apisecret);
         
     | 
| 
      
 708 
     | 
    
         
            +
                  Janus.httpAPICall(longpoll, {
         
     | 
| 
      
 709 
     | 
    
         
            +
                    verb: 'GET',
         
     | 
| 
      
 710 
     | 
    
         
            +
                    withCredentials: withCredentials,
         
     | 
| 
      
 711 
     | 
    
         
            +
                    success: handleEvent,
         
     | 
| 
      
 712 
     | 
    
         
            +
                    timeout: longPollTimeout,
         
     | 
| 
      
 713 
     | 
    
         
            +
                    error: function (textStatus, errorThrown) {
         
     | 
| 
      
 714 
     | 
    
         
            +
                      Janus.error(textStatus + ":", errorThrown);
         
     | 
| 
      
 715 
     | 
    
         
            +
                      retries++;
         
     | 
| 
      
 716 
     | 
    
         
            +
                      if (retries > 3) {
         
     | 
| 
      
 717 
     | 
    
         
            +
                        // Did we just lose the server? :-(
         
     | 
| 
      
 718 
     | 
    
         
            +
                        connected = false;
         
     | 
| 
      
 719 
     | 
    
         
            +
                        gatewayCallbacks.error("Lost connection to the server (is it down?)");
         
     | 
| 
      
 720 
     | 
    
         
            +
                        return;
         
     | 
| 
      
 721 
     | 
    
         
            +
                      }
         
     | 
| 
      
 722 
     | 
    
         
            +
                      eventHandler();
         
     | 
| 
      
 723 
     | 
    
         
            +
                    }
         
     | 
| 
      
 724 
     | 
    
         
            +
                  });
         
     | 
| 
      
 725 
     | 
    
         
            +
                }
         
     | 
| 
      
 726 
     | 
    
         
            +
             
     | 
| 
      
 727 
     | 
    
         
            +
                // Private event handler: this will trigger plugin callbacks, if set
         
     | 
| 
      
 728 
     | 
    
         
            +
                function handleEvent(json, skipTimeout) {
         
     | 
| 
      
 729 
     | 
    
         
            +
                  retries = 0;
         
     | 
| 
      
 730 
     | 
    
         
            +
                  if (!websockets && typeof sessionId !== 'undefined' && sessionId !== null && skipTimeout !== true) eventHandler();
         
     | 
| 
      
 731 
     | 
    
         
            +
                  if (!websockets && Janus.isArray(json)) {
         
     | 
| 
      
 732 
     | 
    
         
            +
                    // We got an array: it means we passed a maxev > 1, iterate on all objects
         
     | 
| 
      
 733 
     | 
    
         
            +
                    for (let i = 0; i < json.length; i++) {
         
     | 
| 
      
 734 
     | 
    
         
            +
                      handleEvent(json[i], true);
         
     | 
| 
      
 735 
     | 
    
         
            +
                    }
         
     | 
| 
      
 736 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 737 
     | 
    
         
            +
                  }
         
     | 
| 
      
 738 
     | 
    
         
            +
                  if (json["janus"] === "keepalive") {
         
     | 
| 
      
 739 
     | 
    
         
            +
                    // Nothing happened
         
     | 
| 
      
 740 
     | 
    
         
            +
                    Janus.vdebug("Got a keepalive on session " + sessionId);
         
     | 
| 
      
 741 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 742 
     | 
    
         
            +
                  } else if (json["janus"] === "server_info") {
         
     | 
| 
      
 743 
     | 
    
         
            +
                    // Just info on the Janus instance
         
     | 
| 
      
 744 
     | 
    
         
            +
                    Janus.debug("Got info on the Janus instance");
         
     | 
| 
      
 745 
     | 
    
         
            +
                    Janus.debug(json);
         
     | 
| 
      
 746 
     | 
    
         
            +
                    const transaction = json["transaction"];
         
     | 
| 
      
 747 
     | 
    
         
            +
                    if (transaction) {
         
     | 
| 
      
 748 
     | 
    
         
            +
                      const reportSuccess = transactions.get(transaction);
         
     | 
| 
      
 749 
     | 
    
         
            +
                      if (reportSuccess) reportSuccess(json);
         
     | 
| 
      
 750 
     | 
    
         
            +
                      transactions.delete(transaction);
         
     | 
| 
      
 751 
     | 
    
         
            +
                    }
         
     | 
| 
      
 752 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 753 
     | 
    
         
            +
                  } else if (json["janus"] === "ack") {
         
     | 
| 
      
 754 
     | 
    
         
            +
                    // Just an ack, we can probably ignore
         
     | 
| 
      
 755 
     | 
    
         
            +
                    Janus.debug("Got an ack on session " + sessionId);
         
     | 
| 
      
 756 
     | 
    
         
            +
                    Janus.debug(json);
         
     | 
| 
      
 757 
     | 
    
         
            +
                    const transaction = json["transaction"];
         
     | 
| 
      
 758 
     | 
    
         
            +
                    if (transaction) {
         
     | 
| 
      
 759 
     | 
    
         
            +
                      const reportSuccess = transactions.get(transaction);
         
     | 
| 
      
 760 
     | 
    
         
            +
                      if (reportSuccess) reportSuccess(json);
         
     | 
| 
      
 761 
     | 
    
         
            +
                      transactions.delete(transaction);
         
     | 
| 
      
 762 
     | 
    
         
            +
                    }
         
     | 
| 
      
 763 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 764 
     | 
    
         
            +
                  } else if (json["janus"] === "success") {
         
     | 
| 
      
 765 
     | 
    
         
            +
                    // Success!
         
     | 
| 
      
 766 
     | 
    
         
            +
                    Janus.debug("Got a success on session " + sessionId);
         
     | 
| 
      
 767 
     | 
    
         
            +
                    Janus.debug(json);
         
     | 
| 
      
 768 
     | 
    
         
            +
                    const transaction = json["transaction"];
         
     | 
| 
      
 769 
     | 
    
         
            +
                    if (transaction) {
         
     | 
| 
      
 770 
     | 
    
         
            +
                      const reportSuccess = transactions.get(transaction);
         
     | 
| 
      
 771 
     | 
    
         
            +
                      if (reportSuccess) reportSuccess(json);
         
     | 
| 
      
 772 
     | 
    
         
            +
                      transactions.delete(transaction);
         
     | 
| 
      
 773 
     | 
    
         
            +
                    }
         
     | 
| 
      
 774 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 775 
     | 
    
         
            +
                  } else if (json["janus"] === "trickle") {
         
     | 
| 
      
 776 
     | 
    
         
            +
                    // We got a trickle candidate from Janus
         
     | 
| 
      
 777 
     | 
    
         
            +
                    const sender = json["sender"];
         
     | 
| 
      
 778 
     | 
    
         
            +
                    if (!sender) {
         
     | 
| 
      
 779 
     | 
    
         
            +
                      Janus.warn("Missing sender...");
         
     | 
| 
      
 780 
     | 
    
         
            +
                      return;
         
     | 
| 
      
 781 
     | 
    
         
            +
                    }
         
     | 
| 
      
 782 
     | 
    
         
            +
                    const pluginHandle = pluginHandles.get(sender);
         
     | 
| 
      
 783 
     | 
    
         
            +
                    if (!pluginHandle) {
         
     | 
| 
      
 784 
     | 
    
         
            +
                      Janus.debug("This handle is not attached to this session");
         
     | 
| 
      
 785 
     | 
    
         
            +
                      return;
         
     | 
| 
      
 786 
     | 
    
         
            +
                    }
         
     | 
| 
      
 787 
     | 
    
         
            +
                    let candidate = json["candidate"];
         
     | 
| 
      
 788 
     | 
    
         
            +
                    Janus.debug("Got a trickled candidate on session " + sessionId);
         
     | 
| 
      
 789 
     | 
    
         
            +
                    Janus.debug(candidate);
         
     | 
| 
      
 790 
     | 
    
         
            +
                    let config = pluginHandle.webrtcStuff;
         
     | 
| 
      
 791 
     | 
    
         
            +
                    if (config.pc && config.remoteSdp) {
         
     | 
| 
      
 792 
     | 
    
         
            +
                      // Add candidate right now
         
     | 
| 
      
 793 
     | 
    
         
            +
                      Janus.debug("Adding remote candidate:", candidate);
         
     | 
| 
      
 794 
     | 
    
         
            +
                      if (!candidate || candidate.completed === true) {
         
     | 
| 
      
 795 
     | 
    
         
            +
                        // end-of-candidates
         
     | 
| 
      
 796 
     | 
    
         
            +
                        config.pc.addIceCandidate(Janus.endOfCandidates);
         
     | 
| 
      
 797 
     | 
    
         
            +
                      } else {
         
     | 
| 
      
 798 
     | 
    
         
            +
                        // New candidate
         
     | 
| 
      
 799 
     | 
    
         
            +
                        config.pc.addIceCandidate(candidate);
         
     | 
| 
      
 800 
     | 
    
         
            +
                      }
         
     | 
| 
      
 801 
     | 
    
         
            +
                    } else {
         
     | 
| 
      
 802 
     | 
    
         
            +
                      // We didn't do setRemoteDescription (trickle got here before the offer?)
         
     | 
| 
      
 803 
     | 
    
         
            +
                      Janus.debug("We didn't do setRemoteDescription (trickle got here before the offer?), caching candidate");
         
     | 
| 
      
 804 
     | 
    
         
            +
                      if (!config.candidates) config.candidates = [];
         
     | 
| 
      
 805 
     | 
    
         
            +
                      config.candidates.push(candidate);
         
     | 
| 
      
 806 
     | 
    
         
            +
                      Janus.debug(config.candidates);
         
     | 
| 
      
 807 
     | 
    
         
            +
                    }
         
     | 
| 
      
 808 
     | 
    
         
            +
                  } else if (json["janus"] === "webrtcup") {
         
     | 
| 
      
 809 
     | 
    
         
            +
                    // The PeerConnection with the server is up! Notify this
         
     | 
| 
      
 810 
     | 
    
         
            +
                    Janus.debug("Got a webrtcup event on session " + sessionId);
         
     | 
| 
      
 811 
     | 
    
         
            +
                    Janus.debug(json);
         
     | 
| 
      
 812 
     | 
    
         
            +
                    const sender = json["sender"];
         
     | 
| 
      
 813 
     | 
    
         
            +
                    if (!sender) {
         
     | 
| 
      
 814 
     | 
    
         
            +
                      Janus.warn("Missing sender...");
         
     | 
| 
      
 815 
     | 
    
         
            +
                      return;
         
     | 
| 
      
 816 
     | 
    
         
            +
                    }
         
     | 
| 
      
 817 
     | 
    
         
            +
                    const pluginHandle = pluginHandles.get(sender);
         
     | 
| 
      
 818 
     | 
    
         
            +
                    if (!pluginHandle) {
         
     | 
| 
      
 819 
     | 
    
         
            +
                      Janus.debug("This handle is not attached to this session");
         
     | 
| 
      
 820 
     | 
    
         
            +
                      return;
         
     | 
| 
      
 821 
     | 
    
         
            +
                    }
         
     | 
| 
      
 822 
     | 
    
         
            +
                    pluginHandle.webrtcState(true);
         
     | 
| 
      
 823 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 824 
     | 
    
         
            +
                  } else if (json["janus"] === "hangup") {
         
     | 
| 
      
 825 
     | 
    
         
            +
                    // A plugin asked the core to hangup a PeerConnection on one of our handles
         
     | 
| 
      
 826 
     | 
    
         
            +
                    Janus.debug("Got a hangup event on session " + sessionId);
         
     | 
| 
      
 827 
     | 
    
         
            +
                    Janus.debug(json);
         
     | 
| 
      
 828 
     | 
    
         
            +
                    const sender = json["sender"];
         
     | 
| 
      
 829 
     | 
    
         
            +
                    if (!sender) {
         
     | 
| 
      
 830 
     | 
    
         
            +
                      Janus.warn("Missing sender...");
         
     | 
| 
      
 831 
     | 
    
         
            +
                      return;
         
     | 
| 
      
 832 
     | 
    
         
            +
                    }
         
     | 
| 
      
 833 
     | 
    
         
            +
                    const pluginHandle = pluginHandles.get(sender);
         
     | 
| 
      
 834 
     | 
    
         
            +
                    if (!pluginHandle) {
         
     | 
| 
      
 835 
     | 
    
         
            +
                      Janus.debug("This handle is not attached to this session");
         
     | 
| 
      
 836 
     | 
    
         
            +
                      return;
         
     | 
| 
      
 837 
     | 
    
         
            +
                    }
         
     | 
| 
      
 838 
     | 
    
         
            +
                    pluginHandle.webrtcState(false, json["reason"]);
         
     | 
| 
      
 839 
     | 
    
         
            +
                    pluginHandle.hangup();
         
     | 
| 
      
 840 
     | 
    
         
            +
                  } else if (json["janus"] === "detached") {
         
     | 
| 
      
 841 
     | 
    
         
            +
                    // A plugin asked the core to detach one of our handles
         
     | 
| 
      
 842 
     | 
    
         
            +
                    Janus.debug("Got a detached event on session " + sessionId);
         
     | 
| 
      
 843 
     | 
    
         
            +
                    Janus.debug(json);
         
     | 
| 
      
 844 
     | 
    
         
            +
                    const sender = json["sender"];
         
     | 
| 
      
 845 
     | 
    
         
            +
                    if (!sender) {
         
     | 
| 
      
 846 
     | 
    
         
            +
                      Janus.warn("Missing sender...");
         
     | 
| 
      
 847 
     | 
    
         
            +
                      return;
         
     | 
| 
      
 848 
     | 
    
         
            +
                    }
         
     | 
| 
      
 849 
     | 
    
         
            +
                    const pluginHandle = pluginHandles.get(sender);
         
     | 
| 
      
 850 
     | 
    
         
            +
                    if (!pluginHandle) {
         
     | 
| 
      
 851 
     | 
    
         
            +
                      // Don't warn here because destroyHandle causes this situation.
         
     | 
| 
      
 852 
     | 
    
         
            +
                      return;
         
     | 
| 
      
 853 
     | 
    
         
            +
                    }
         
     | 
| 
      
 854 
     | 
    
         
            +
                    pluginHandle.ondetached();
         
     | 
| 
      
 855 
     | 
    
         
            +
                    pluginHandle.detach();
         
     | 
| 
      
 856 
     | 
    
         
            +
                  } else if (json["janus"] === "media") {
         
     | 
| 
      
 857 
     | 
    
         
            +
                    // Media started/stopped flowing
         
     | 
| 
      
 858 
     | 
    
         
            +
                    Janus.debug("Got a media event on session " + sessionId);
         
     | 
| 
      
 859 
     | 
    
         
            +
                    Janus.debug(json);
         
     | 
| 
      
 860 
     | 
    
         
            +
                    const sender = json["sender"];
         
     | 
| 
      
 861 
     | 
    
         
            +
                    if (!sender) {
         
     | 
| 
      
 862 
     | 
    
         
            +
                      Janus.warn("Missing sender...");
         
     | 
| 
      
 863 
     | 
    
         
            +
                      return;
         
     | 
| 
      
 864 
     | 
    
         
            +
                    }
         
     | 
| 
      
 865 
     | 
    
         
            +
                    const pluginHandle = pluginHandles.get(sender);
         
     | 
| 
      
 866 
     | 
    
         
            +
                    if (!pluginHandle) {
         
     | 
| 
      
 867 
     | 
    
         
            +
                      Janus.debug("This handle is not attached to this session");
         
     | 
| 
      
 868 
     | 
    
         
            +
                      return;
         
     | 
| 
      
 869 
     | 
    
         
            +
                    }
         
     | 
| 
      
 870 
     | 
    
         
            +
                    pluginHandle.mediaState(json["type"], json["receiving"], json["mid"]);
         
     | 
| 
      
 871 
     | 
    
         
            +
                  } else if (json["janus"] === "slowlink") {
         
     | 
| 
      
 872 
     | 
    
         
            +
                    Janus.debug("Got a slowlink event on session " + sessionId);
         
     | 
| 
      
 873 
     | 
    
         
            +
                    Janus.debug(json);
         
     | 
| 
      
 874 
     | 
    
         
            +
                    // Trouble uplink or downlink
         
     | 
| 
      
 875 
     | 
    
         
            +
                    const sender = json["sender"];
         
     | 
| 
      
 876 
     | 
    
         
            +
                    if (!sender) {
         
     | 
| 
      
 877 
     | 
    
         
            +
                      Janus.warn("Missing sender...");
         
     | 
| 
      
 878 
     | 
    
         
            +
                      return;
         
     | 
| 
      
 879 
     | 
    
         
            +
                    }
         
     | 
| 
      
 880 
     | 
    
         
            +
                    const pluginHandle = pluginHandles.get(sender);
         
     | 
| 
      
 881 
     | 
    
         
            +
                    if (!pluginHandle) {
         
     | 
| 
      
 882 
     | 
    
         
            +
                      Janus.debug("This handle is not attached to this session");
         
     | 
| 
      
 883 
     | 
    
         
            +
                      return;
         
     | 
| 
      
 884 
     | 
    
         
            +
                    }
         
     | 
| 
      
 885 
     | 
    
         
            +
                    pluginHandle.slowLink(json["uplink"], json["lost"], json["mid"]);
         
     | 
| 
      
 886 
     | 
    
         
            +
                  } else if (json["janus"] === "error") {
         
     | 
| 
      
 887 
     | 
    
         
            +
                    // Oops, something wrong happened
         
     | 
| 
      
 888 
     | 
    
         
            +
                    Janus.error("Ooops: " + json["error"].code + " " + json["error"].reason); // FIXME
         
     | 
| 
      
 889 
     | 
    
         
            +
                    Janus.debug(json);
         
     | 
| 
      
 890 
     | 
    
         
            +
                    let transaction = json["transaction"];
         
     | 
| 
      
 891 
     | 
    
         
            +
                    if (transaction) {
         
     | 
| 
      
 892 
     | 
    
         
            +
                      let reportSuccess = transactions.get(transaction);
         
     | 
| 
      
 893 
     | 
    
         
            +
                      if (reportSuccess) {
         
     | 
| 
      
 894 
     | 
    
         
            +
                        reportSuccess(json);
         
     | 
| 
      
 895 
     | 
    
         
            +
                      }
         
     | 
| 
      
 896 
     | 
    
         
            +
                      transactions.delete(transaction);
         
     | 
| 
      
 897 
     | 
    
         
            +
                    }
         
     | 
| 
      
 898 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 899 
     | 
    
         
            +
                  } else if (json["janus"] === "event") {
         
     | 
| 
      
 900 
     | 
    
         
            +
                    Janus.debug("Got a plugin event on session " + sessionId);
         
     | 
| 
      
 901 
     | 
    
         
            +
                    Janus.debug(json);
         
     | 
| 
      
 902 
     | 
    
         
            +
                    const sender = json["sender"];
         
     | 
| 
      
 903 
     | 
    
         
            +
                    if (!sender) {
         
     | 
| 
      
 904 
     | 
    
         
            +
                      Janus.warn("Missing sender...");
         
     | 
| 
      
 905 
     | 
    
         
            +
                      return;
         
     | 
| 
      
 906 
     | 
    
         
            +
                    }
         
     | 
| 
      
 907 
     | 
    
         
            +
                    let plugindata = json["plugindata"];
         
     | 
| 
      
 908 
     | 
    
         
            +
                    if (!plugindata) {
         
     | 
| 
      
 909 
     | 
    
         
            +
                      Janus.warn("Missing plugindata...");
         
     | 
| 
      
 910 
     | 
    
         
            +
                      return;
         
     | 
| 
      
 911 
     | 
    
         
            +
                    }
         
     | 
| 
      
 912 
     | 
    
         
            +
                    Janus.debug("  -- Event is coming from " + sender + " (" + plugindata["plugin"] + ")");
         
     | 
| 
      
 913 
     | 
    
         
            +
                    let data = plugindata["data"];
         
     | 
| 
      
 914 
     | 
    
         
            +
                    Janus.debug(data);
         
     | 
| 
      
 915 
     | 
    
         
            +
                    const pluginHandle = pluginHandles.get(sender);
         
     | 
| 
      
 916 
     | 
    
         
            +
                    if (!pluginHandle) {
         
     | 
| 
      
 917 
     | 
    
         
            +
                      Janus.warn("This handle is not attached to this session");
         
     | 
| 
      
 918 
     | 
    
         
            +
                      return;
         
     | 
| 
      
 919 
     | 
    
         
            +
                    }
         
     | 
| 
      
 920 
     | 
    
         
            +
                    let jsep = json["jsep"];
         
     | 
| 
      
 921 
     | 
    
         
            +
                    if (jsep) {
         
     | 
| 
      
 922 
     | 
    
         
            +
                      Janus.debug("Handling SDP as well...");
         
     | 
| 
      
 923 
     | 
    
         
            +
                      Janus.debug(jsep);
         
     | 
| 
      
 924 
     | 
    
         
            +
                    }
         
     | 
| 
      
 925 
     | 
    
         
            +
                    let callback = pluginHandle.onmessage;
         
     | 
| 
      
 926 
     | 
    
         
            +
                    if (callback) {
         
     | 
| 
      
 927 
     | 
    
         
            +
                      Janus.debug("Notifying application...");
         
     | 
| 
      
 928 
     | 
    
         
            +
                      // Send to callback specified when attaching plugin handle
         
     | 
| 
      
 929 
     | 
    
         
            +
                      callback(data, jsep);
         
     | 
| 
      
 930 
     | 
    
         
            +
                    } else {
         
     | 
| 
      
 931 
     | 
    
         
            +
                      // Send to generic callback (?)
         
     | 
| 
      
 932 
     | 
    
         
            +
                      Janus.debug("No provided notification callback");
         
     | 
| 
      
 933 
     | 
    
         
            +
                    }
         
     | 
| 
      
 934 
     | 
    
         
            +
                  } else if (json["janus"] === "timeout") {
         
     | 
| 
      
 935 
     | 
    
         
            +
                    Janus.error("Timeout on session " + sessionId);
         
     | 
| 
      
 936 
     | 
    
         
            +
                    Janus.debug(json);
         
     | 
| 
      
 937 
     | 
    
         
            +
                    if (websockets) {
         
     | 
| 
      
 938 
     | 
    
         
            +
                      ws.close(3504, "Gateway timeout");
         
     | 
| 
      
 939 
     | 
    
         
            +
                    }
         
     | 
| 
      
 940 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 941 
     | 
    
         
            +
                  } else {
         
     | 
| 
      
 942 
     | 
    
         
            +
                    Janus.warn("Unknown message/event  '" + json["janus"] + "' on session " + sessionId);
         
     | 
| 
      
 943 
     | 
    
         
            +
                    Janus.debug(json);
         
     | 
| 
      
 944 
     | 
    
         
            +
                  }
         
     | 
| 
      
 945 
     | 
    
         
            +
                }
         
     | 
| 
      
 946 
     | 
    
         
            +
             
     | 
| 
      
 947 
     | 
    
         
            +
                // Private helper to send keep-alive messages on WebSockets
         
     | 
| 
      
 948 
     | 
    
         
            +
                function keepAlive() {
         
     | 
| 
      
 949 
     | 
    
         
            +
                  if (!server || !websockets || !connected) return;
         
     | 
| 
      
 950 
     | 
    
         
            +
                  wsKeepaliveTimeoutId = setTimeout(keepAlive, keepAlivePeriod);
         
     | 
| 
      
 951 
     | 
    
         
            +
                  let request = {
         
     | 
| 
      
 952 
     | 
    
         
            +
                    "janus": "keepalive",
         
     | 
| 
      
 953 
     | 
    
         
            +
                    "session_id": sessionId,
         
     | 
| 
      
 954 
     | 
    
         
            +
                    "transaction": Janus.randomString(12)
         
     | 
| 
      
 955 
     | 
    
         
            +
                  };
         
     | 
| 
      
 956 
     | 
    
         
            +
                  if (token) request["token"] = token;
         
     | 
| 
      
 957 
     | 
    
         
            +
                  if (apisecret) request["apisecret"] = apisecret;
         
     | 
| 
      
 958 
     | 
    
         
            +
                  ws.send(JSON.stringify(request));
         
     | 
| 
      
 959 
     | 
    
         
            +
                }
         
     | 
| 
      
 960 
     | 
    
         
            +
             
     | 
| 
      
 961 
     | 
    
         
            +
                // Private method to create a session
         
     | 
| 
      
 962 
     | 
    
         
            +
                function createSession(callbacks) {
         
     | 
| 
      
 963 
     | 
    
         
            +
                  let transaction = Janus.randomString(12);
         
     | 
| 
      
 964 
     | 
    
         
            +
                  let request = {
         
     | 
| 
      
 965 
     | 
    
         
            +
                    "janus": "create",
         
     | 
| 
      
 966 
     | 
    
         
            +
                    "transaction": transaction
         
     | 
| 
      
 967 
     | 
    
         
            +
                  };
         
     | 
| 
      
 968 
     | 
    
         
            +
                  if (callbacks["reconnect"]) {
         
     | 
| 
      
 969 
     | 
    
         
            +
                    // We're reconnecting, claim the session
         
     | 
| 
      
 970 
     | 
    
         
            +
                    connected = false;
         
     | 
| 
      
 971 
     | 
    
         
            +
                    request["janus"] = "claim";
         
     | 
| 
      
 972 
     | 
    
         
            +
                    request["session_id"] = sessionId;
         
     | 
| 
      
 973 
     | 
    
         
            +
                    // If we were using websockets, ignore the old connection
         
     | 
| 
      
 974 
     | 
    
         
            +
                    if (ws) {
         
     | 
| 
      
 975 
     | 
    
         
            +
                      ws.onopen = null;
         
     | 
| 
      
 976 
     | 
    
         
            +
                      ws.onerror = null;
         
     | 
| 
      
 977 
     | 
    
         
            +
                      ws.onclose = null;
         
     | 
| 
      
 978 
     | 
    
         
            +
                      if (wsKeepaliveTimeoutId) {
         
     | 
| 
      
 979 
     | 
    
         
            +
                        clearTimeout(wsKeepaliveTimeoutId);
         
     | 
| 
      
 980 
     | 
    
         
            +
                        wsKeepaliveTimeoutId = null;
         
     | 
| 
      
 981 
     | 
    
         
            +
                      }
         
     | 
| 
      
 982 
     | 
    
         
            +
                    }
         
     | 
| 
      
 983 
     | 
    
         
            +
                  }
         
     | 
| 
      
 984 
     | 
    
         
            +
                  if (token) request["token"] = token;
         
     | 
| 
      
 985 
     | 
    
         
            +
                  if (apisecret) request["apisecret"] = apisecret;
         
     | 
| 
      
 986 
     | 
    
         
            +
                  if (!server && Janus.isArray(servers)) {
         
     | 
| 
      
 987 
     | 
    
         
            +
                    // We still need to find a working server from the list we were given
         
     | 
| 
      
 988 
     | 
    
         
            +
                    server = servers[serversIndex];
         
     | 
| 
      
 989 
     | 
    
         
            +
                    if (server.indexOf("ws") === 0) {
         
     | 
| 
      
 990 
     | 
    
         
            +
                      websockets = true;
         
     | 
| 
      
 991 
     | 
    
         
            +
                      Janus.log("Server #" + (serversIndex + 1) + ": trying WebSockets to contact Janus (" + server + ")");
         
     | 
| 
      
 992 
     | 
    
         
            +
                    } else {
         
     | 
| 
      
 993 
     | 
    
         
            +
                      websockets = false;
         
     | 
| 
      
 994 
     | 
    
         
            +
                      Janus.log("Server #" + (serversIndex + 1) + ": trying REST API to contact Janus (" + server + ")");
         
     | 
| 
      
 995 
     | 
    
         
            +
                    }
         
     | 
| 
      
 996 
     | 
    
         
            +
                  }
         
     | 
| 
      
 997 
     | 
    
         
            +
                  if (websockets) {
         
     | 
| 
      
 998 
     | 
    
         
            +
                    ws = Janus.newWebSocket(server, 'janus-protocol');
         
     | 
| 
      
 999 
     | 
    
         
            +
                    wsHandlers = {
         
     | 
| 
      
 1000 
     | 
    
         
            +
                      'error': function () {
         
     | 
| 
      
 1001 
     | 
    
         
            +
                        Janus.error("Error connecting to the Janus WebSockets server... " + server);
         
     | 
| 
      
 1002 
     | 
    
         
            +
                        if (Janus.isArray(servers) && !callbacks["reconnect"]) {
         
     | 
| 
      
 1003 
     | 
    
         
            +
                          serversIndex++;
         
     | 
| 
      
 1004 
     | 
    
         
            +
                          if (serversIndex === servers.length) {
         
     | 
| 
      
 1005 
     | 
    
         
            +
                            // We tried all the servers the user gave us and they all failed
         
     | 
| 
      
 1006 
     | 
    
         
            +
                            callbacks.error("Error connecting to any of the provided Janus servers: Is the server down?");
         
     | 
| 
      
 1007 
     | 
    
         
            +
                            return;
         
     | 
| 
      
 1008 
     | 
    
         
            +
                          }
         
     | 
| 
      
 1009 
     | 
    
         
            +
                          // Let's try the next server
         
     | 
| 
      
 1010 
     | 
    
         
            +
                          server = null;
         
     | 
| 
      
 1011 
     | 
    
         
            +
                          setTimeout(function () {
         
     | 
| 
      
 1012 
     | 
    
         
            +
                            createSession(callbacks);
         
     | 
| 
      
 1013 
     | 
    
         
            +
                          }, 200);
         
     | 
| 
      
 1014 
     | 
    
         
            +
                          return;
         
     | 
| 
      
 1015 
     | 
    
         
            +
                        }
         
     | 
| 
      
 1016 
     | 
    
         
            +
                        callbacks.error("Error connecting to the Janus WebSockets server: Is the server down?");
         
     | 
| 
      
 1017 
     | 
    
         
            +
                      },
         
     | 
| 
      
 1018 
     | 
    
         
            +
                      'open': function () {
         
     | 
| 
      
 1019 
     | 
    
         
            +
                        // We need to be notified about the success
         
     | 
| 
      
 1020 
     | 
    
         
            +
                        transactions.set(transaction, function (json) {
         
     | 
| 
      
 1021 
     | 
    
         
            +
                          Janus.debug(json);
         
     | 
| 
      
 1022 
     | 
    
         
            +
                          if (json["janus"] !== "success") {
         
     | 
| 
      
 1023 
     | 
    
         
            +
                            Janus.error("Ooops: " + json["error"].code + " " + json["error"].reason); // FIXME
         
     | 
| 
      
 1024 
     | 
    
         
            +
                            callbacks.error(json["error"].reason);
         
     | 
| 
      
 1025 
     | 
    
         
            +
                            return;
         
     | 
| 
      
 1026 
     | 
    
         
            +
                          }
         
     | 
| 
      
 1027 
     | 
    
         
            +
                          wsKeepaliveTimeoutId = setTimeout(keepAlive, keepAlivePeriod);
         
     | 
| 
      
 1028 
     | 
    
         
            +
                          connected = true;
         
     | 
| 
      
 1029 
     | 
    
         
            +
                          sessionId = json["session_id"] ? json["session_id"] : json.data["id"];
         
     | 
| 
      
 1030 
     | 
    
         
            +
                          if (callbacks["reconnect"]) {
         
     | 
| 
      
 1031 
     | 
    
         
            +
                            Janus.log("Claimed session: " + sessionId);
         
     | 
| 
      
 1032 
     | 
    
         
            +
                          } else {
         
     | 
| 
      
 1033 
     | 
    
         
            +
                            Janus.log("Created session: " + sessionId);
         
     | 
| 
      
 1034 
     | 
    
         
            +
                          }
         
     | 
| 
      
 1035 
     | 
    
         
            +
                          Janus.sessions.set(sessionId, that);
         
     | 
| 
      
 1036 
     | 
    
         
            +
                          callbacks.success();
         
     | 
| 
      
 1037 
     | 
    
         
            +
                        });
         
     | 
| 
      
 1038 
     | 
    
         
            +
                        ws.send(JSON.stringify(request));
         
     | 
| 
      
 1039 
     | 
    
         
            +
                      },
         
     | 
| 
      
 1040 
     | 
    
         
            +
                      'message': function (event) {
         
     | 
| 
      
 1041 
     | 
    
         
            +
                        handleEvent(JSON.parse(event.data));
         
     | 
| 
      
 1042 
     | 
    
         
            +
                      },
         
     | 
| 
      
 1043 
     | 
    
         
            +
                      'close': function () {
         
     | 
| 
      
 1044 
     | 
    
         
            +
                        if (!server || !connected) {
         
     | 
| 
      
 1045 
     | 
    
         
            +
                          return;
         
     | 
| 
      
 1046 
     | 
    
         
            +
                        }
         
     | 
| 
      
 1047 
     | 
    
         
            +
                        connected = false;
         
     | 
| 
      
 1048 
     | 
    
         
            +
                        // FIXME What if this is called when the page is closed?
         
     | 
| 
      
 1049 
     | 
    
         
            +
                        gatewayCallbacks.error("Lost connection to the server (is it down?)");
         
     | 
| 
      
 1050 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1051 
     | 
    
         
            +
                    };
         
     | 
| 
      
 1052 
     | 
    
         
            +
                    for (let eventName in wsHandlers) {
         
     | 
| 
      
 1053 
     | 
    
         
            +
                      ws.addEventListener(eventName, wsHandlers[eventName]);
         
     | 
| 
      
 1054 
     | 
    
         
            +
                    }
         
     | 
| 
      
 1055 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 1056 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1057 
     | 
    
         
            +
                  Janus.httpAPICall(server, {
         
     | 
| 
      
 1058 
     | 
    
         
            +
                    verb: 'POST',
         
     | 
| 
      
 1059 
     | 
    
         
            +
                    withCredentials: withCredentials,
         
     | 
| 
      
 1060 
     | 
    
         
            +
                    body: request,
         
     | 
| 
      
 1061 
     | 
    
         
            +
                    success: function (json) {
         
     | 
| 
      
 1062 
     | 
    
         
            +
                      Janus.debug(json);
         
     | 
| 
      
 1063 
     | 
    
         
            +
                      if (json["janus"] !== "success") {
         
     | 
| 
      
 1064 
     | 
    
         
            +
                        Janus.error("Ooops: " + json["error"].code + " " + json["error"].reason); // FIXME
         
     | 
| 
      
 1065 
     | 
    
         
            +
                        callbacks.error(json["error"].reason);
         
     | 
| 
      
 1066 
     | 
    
         
            +
                        return;
         
     | 
| 
      
 1067 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1068 
     | 
    
         
            +
                      connected = true;
         
     | 
| 
      
 1069 
     | 
    
         
            +
                      sessionId = json["session_id"] ? json["session_id"] : json.data["id"];
         
     | 
| 
      
 1070 
     | 
    
         
            +
                      if (callbacks["reconnect"]) {
         
     | 
| 
      
 1071 
     | 
    
         
            +
                        Janus.log("Claimed session: " + sessionId);
         
     | 
| 
      
 1072 
     | 
    
         
            +
                      } else {
         
     | 
| 
      
 1073 
     | 
    
         
            +
                        Janus.log("Created session: " + sessionId);
         
     | 
| 
      
 1074 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1075 
     | 
    
         
            +
                      Janus.sessions.set(sessionId, that);
         
     | 
| 
      
 1076 
     | 
    
         
            +
                      eventHandler();
         
     | 
| 
      
 1077 
     | 
    
         
            +
                      callbacks.success();
         
     | 
| 
      
 1078 
     | 
    
         
            +
                    },
         
     | 
| 
      
 1079 
     | 
    
         
            +
                    error: function (textStatus, errorThrown) {
         
     | 
| 
      
 1080 
     | 
    
         
            +
                      Janus.error(textStatus + ":", errorThrown); // FIXME
         
     | 
| 
      
 1081 
     | 
    
         
            +
                      if (Janus.isArray(servers) && !callbacks["reconnect"]) {
         
     | 
| 
      
 1082 
     | 
    
         
            +
                        serversIndex++;
         
     | 
| 
      
 1083 
     | 
    
         
            +
                        if (serversIndex === servers.length) {
         
     | 
| 
      
 1084 
     | 
    
         
            +
                          // We tried all the servers the user gave us and they all failed
         
     | 
| 
      
 1085 
     | 
    
         
            +
                          callbacks.error("Error connecting to any of the provided Janus servers: Is the server down?");
         
     | 
| 
      
 1086 
     | 
    
         
            +
                          return;
         
     | 
| 
      
 1087 
     | 
    
         
            +
                        }
         
     | 
| 
      
 1088 
     | 
    
         
            +
                        // Let's try the next server
         
     | 
| 
      
 1089 
     | 
    
         
            +
                        server = null;
         
     | 
| 
      
 1090 
     | 
    
         
            +
                        setTimeout(function () {
         
     | 
| 
      
 1091 
     | 
    
         
            +
                          createSession(callbacks);
         
     | 
| 
      
 1092 
     | 
    
         
            +
                        }, 200);
         
     | 
| 
      
 1093 
     | 
    
         
            +
                        return;
         
     | 
| 
      
 1094 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1095 
     | 
    
         
            +
                      if (errorThrown === "") callbacks.error(textStatus + ": Is the server down?");else if (errorThrown && errorThrown.error) callbacks.error(textStatus + ": " + errorThrown.error.message);else callbacks.error(textStatus + ": " + errorThrown);
         
     | 
| 
      
 1096 
     | 
    
         
            +
                    }
         
     | 
| 
      
 1097 
     | 
    
         
            +
                  });
         
     | 
| 
      
 1098 
     | 
    
         
            +
                }
         
     | 
| 
      
 1099 
     | 
    
         
            +
             
     | 
| 
      
 1100 
     | 
    
         
            +
                // Private method to get info on the server
         
     | 
| 
      
 1101 
     | 
    
         
            +
                function getInfo(callbacks) {
         
     | 
| 
      
 1102 
     | 
    
         
            +
                  callbacks = callbacks || {};
         
     | 
| 
      
 1103 
     | 
    
         
            +
                  // FIXME This method triggers a success even when we fail
         
     | 
| 
      
 1104 
     | 
    
         
            +
                  callbacks.success = typeof callbacks.success == "function" ? callbacks.success : Janus.noop;
         
     | 
| 
      
 1105 
     | 
    
         
            +
                  callbacks.error = typeof callbacks.error == "function" ? callbacks.error : Janus.noop;
         
     | 
| 
      
 1106 
     | 
    
         
            +
                  Janus.log("Getting info on Janus instance");
         
     | 
| 
      
 1107 
     | 
    
         
            +
                  if (!connected) {
         
     | 
| 
      
 1108 
     | 
    
         
            +
                    Janus.warn("Is the server down? (connected=false)");
         
     | 
| 
      
 1109 
     | 
    
         
            +
                    callbacks.error("Is the server down? (connected=false)");
         
     | 
| 
      
 1110 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 1111 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1112 
     | 
    
         
            +
                  // We just need to send an "info" request
         
     | 
| 
      
 1113 
     | 
    
         
            +
                  let transaction = Janus.randomString(12);
         
     | 
| 
      
 1114 
     | 
    
         
            +
                  let request = {
         
     | 
| 
      
 1115 
     | 
    
         
            +
                    "janus": "info",
         
     | 
| 
      
 1116 
     | 
    
         
            +
                    "transaction": transaction
         
     | 
| 
      
 1117 
     | 
    
         
            +
                  };
         
     | 
| 
      
 1118 
     | 
    
         
            +
                  if (token) request["token"] = token;
         
     | 
| 
      
 1119 
     | 
    
         
            +
                  if (apisecret) request["apisecret"] = apisecret;
         
     | 
| 
      
 1120 
     | 
    
         
            +
                  if (websockets) {
         
     | 
| 
      
 1121 
     | 
    
         
            +
                    transactions.set(transaction, function (json) {
         
     | 
| 
      
 1122 
     | 
    
         
            +
                      Janus.log("Server info:");
         
     | 
| 
      
 1123 
     | 
    
         
            +
                      Janus.debug(json);
         
     | 
| 
      
 1124 
     | 
    
         
            +
                      if (json["janus"] !== "server_info") {
         
     | 
| 
      
 1125 
     | 
    
         
            +
                        Janus.error("Ooops: " + json["error"].code + " " + json["error"].reason); // FIXME
         
     | 
| 
      
 1126 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1127 
     | 
    
         
            +
                      callbacks.success(json);
         
     | 
| 
      
 1128 
     | 
    
         
            +
                    });
         
     | 
| 
      
 1129 
     | 
    
         
            +
                    ws.send(JSON.stringify(request));
         
     | 
| 
      
 1130 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 1131 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1132 
     | 
    
         
            +
                  Janus.httpAPICall(server, {
         
     | 
| 
      
 1133 
     | 
    
         
            +
                    verb: 'POST',
         
     | 
| 
      
 1134 
     | 
    
         
            +
                    withCredentials: withCredentials,
         
     | 
| 
      
 1135 
     | 
    
         
            +
                    body: request,
         
     | 
| 
      
 1136 
     | 
    
         
            +
                    success: function (json) {
         
     | 
| 
      
 1137 
     | 
    
         
            +
                      Janus.log("Server info:");
         
     | 
| 
      
 1138 
     | 
    
         
            +
                      Janus.debug(json);
         
     | 
| 
      
 1139 
     | 
    
         
            +
                      if (json["janus"] !== "server_info") {
         
     | 
| 
      
 1140 
     | 
    
         
            +
                        Janus.error("Ooops: " + json["error"].code + " " + json["error"].reason); // FIXME
         
     | 
| 
      
 1141 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1142 
     | 
    
         
            +
                      callbacks.success(json);
         
     | 
| 
      
 1143 
     | 
    
         
            +
                    },
         
     | 
| 
      
 1144 
     | 
    
         
            +
                    error: function (textStatus, errorThrown) {
         
     | 
| 
      
 1145 
     | 
    
         
            +
                      Janus.error(textStatus + ":", errorThrown); // FIXME
         
     | 
| 
      
 1146 
     | 
    
         
            +
                      if (errorThrown === "") callbacks.error(textStatus + ": Is the server down?");else callbacks.error(textStatus + ": " + errorThrown);
         
     | 
| 
      
 1147 
     | 
    
         
            +
                    }
         
     | 
| 
      
 1148 
     | 
    
         
            +
                  });
         
     | 
| 
      
 1149 
     | 
    
         
            +
                }
         
     | 
| 
      
 1150 
     | 
    
         
            +
             
     | 
| 
      
 1151 
     | 
    
         
            +
                // Private method to destroy a session
         
     | 
| 
      
 1152 
     | 
    
         
            +
                function destroySession(callbacks) {
         
     | 
| 
      
 1153 
     | 
    
         
            +
                  callbacks = callbacks || {};
         
     | 
| 
      
 1154 
     | 
    
         
            +
                  // FIXME This method triggers a success even when we fail
         
     | 
| 
      
 1155 
     | 
    
         
            +
                  callbacks.success = typeof callbacks.success == "function" ? callbacks.success : Janus.noop;
         
     | 
| 
      
 1156 
     | 
    
         
            +
                  callbacks.error = typeof callbacks.error == "function" ? callbacks.error : Janus.noop;
         
     | 
| 
      
 1157 
     | 
    
         
            +
                  let unload = callbacks.unload === true;
         
     | 
| 
      
 1158 
     | 
    
         
            +
                  let notifyDestroyed = true;
         
     | 
| 
      
 1159 
     | 
    
         
            +
                  if (typeof callbacks.notifyDestroyed !== 'undefined' && callbacks.notifyDestroyed !== null) notifyDestroyed = callbacks.notifyDestroyed === true;
         
     | 
| 
      
 1160 
     | 
    
         
            +
                  let cleanupHandles = callbacks.cleanupHandles === true;
         
     | 
| 
      
 1161 
     | 
    
         
            +
                  Janus.log("Destroying session " + sessionId + " (unload=" + unload + ")");
         
     | 
| 
      
 1162 
     | 
    
         
            +
                  if (!sessionId) {
         
     | 
| 
      
 1163 
     | 
    
         
            +
                    Janus.warn("No session to destroy");
         
     | 
| 
      
 1164 
     | 
    
         
            +
                    callbacks.success();
         
     | 
| 
      
 1165 
     | 
    
         
            +
                    if (notifyDestroyed) gatewayCallbacks.destroyed();
         
     | 
| 
      
 1166 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 1167 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1168 
     | 
    
         
            +
                  if (cleanupHandles) {
         
     | 
| 
      
 1169 
     | 
    
         
            +
                    for (const handleId of pluginHandles.keys()) destroyHandle(handleId, {
         
     | 
| 
      
 1170 
     | 
    
         
            +
                      noRequest: true
         
     | 
| 
      
 1171 
     | 
    
         
            +
                    });
         
     | 
| 
      
 1172 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1173 
     | 
    
         
            +
                  if (!connected) {
         
     | 
| 
      
 1174 
     | 
    
         
            +
                    Janus.warn("Is the server down? (connected=false)");
         
     | 
| 
      
 1175 
     | 
    
         
            +
                    sessionId = null;
         
     | 
| 
      
 1176 
     | 
    
         
            +
                    callbacks.success();
         
     | 
| 
      
 1177 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 1178 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1179 
     | 
    
         
            +
                  // No need to destroy all handles first, Janus will do that itself
         
     | 
| 
      
 1180 
     | 
    
         
            +
                  let request = {
         
     | 
| 
      
 1181 
     | 
    
         
            +
                    "janus": "destroy",
         
     | 
| 
      
 1182 
     | 
    
         
            +
                    "transaction": Janus.randomString(12)
         
     | 
| 
      
 1183 
     | 
    
         
            +
                  };
         
     | 
| 
      
 1184 
     | 
    
         
            +
                  if (token) request["token"] = token;
         
     | 
| 
      
 1185 
     | 
    
         
            +
                  if (apisecret) request["apisecret"] = apisecret;
         
     | 
| 
      
 1186 
     | 
    
         
            +
                  if (unload) {
         
     | 
| 
      
 1187 
     | 
    
         
            +
                    // We're unloading the page: use sendBeacon for HTTP instead,
         
     | 
| 
      
 1188 
     | 
    
         
            +
                    // or just close the WebSocket connection if we're using that
         
     | 
| 
      
 1189 
     | 
    
         
            +
                    if (websockets) {
         
     | 
| 
      
 1190 
     | 
    
         
            +
                      ws.onclose = null;
         
     | 
| 
      
 1191 
     | 
    
         
            +
                      ws.close();
         
     | 
| 
      
 1192 
     | 
    
         
            +
                      ws = null;
         
     | 
| 
      
 1193 
     | 
    
         
            +
                    } else {
         
     | 
| 
      
 1194 
     | 
    
         
            +
                      navigator.sendBeacon(server + "/" + sessionId, JSON.stringify(request));
         
     | 
| 
      
 1195 
     | 
    
         
            +
                    }
         
     | 
| 
      
 1196 
     | 
    
         
            +
                    Janus.log("Destroyed session:");
         
     | 
| 
      
 1197 
     | 
    
         
            +
                    sessionId = null;
         
     | 
| 
      
 1198 
     | 
    
         
            +
                    connected = false;
         
     | 
| 
      
 1199 
     | 
    
         
            +
                    callbacks.success();
         
     | 
| 
      
 1200 
     | 
    
         
            +
                    if (notifyDestroyed) gatewayCallbacks.destroyed();
         
     | 
| 
      
 1201 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 1202 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1203 
     | 
    
         
            +
                  if (websockets) {
         
     | 
| 
      
 1204 
     | 
    
         
            +
                    request["session_id"] = sessionId;
         
     | 
| 
      
 1205 
     | 
    
         
            +
                    let unbindWebSocket = function () {
         
     | 
| 
      
 1206 
     | 
    
         
            +
                      for (let eventName in wsHandlers) {
         
     | 
| 
      
 1207 
     | 
    
         
            +
                        ws.removeEventListener(eventName, wsHandlers[eventName]);
         
     | 
| 
      
 1208 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1209 
     | 
    
         
            +
                      ws.removeEventListener('message', onUnbindMessage);
         
     | 
| 
      
 1210 
     | 
    
         
            +
                      ws.removeEventListener('error', onUnbindError);
         
     | 
| 
      
 1211 
     | 
    
         
            +
                      if (wsKeepaliveTimeoutId) {
         
     | 
| 
      
 1212 
     | 
    
         
            +
                        clearTimeout(wsKeepaliveTimeoutId);
         
     | 
| 
      
 1213 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1214 
     | 
    
         
            +
                      ws.close();
         
     | 
| 
      
 1215 
     | 
    
         
            +
                    };
         
     | 
| 
      
 1216 
     | 
    
         
            +
                    let onUnbindMessage = function (event) {
         
     | 
| 
      
 1217 
     | 
    
         
            +
                      let data = JSON.parse(event.data);
         
     | 
| 
      
 1218 
     | 
    
         
            +
                      if (data.session_id == request.session_id && data.transaction == request.transaction) {
         
     | 
| 
      
 1219 
     | 
    
         
            +
                        unbindWebSocket();
         
     | 
| 
      
 1220 
     | 
    
         
            +
                        callbacks.success();
         
     | 
| 
      
 1221 
     | 
    
         
            +
                        if (notifyDestroyed) gatewayCallbacks.destroyed();
         
     | 
| 
      
 1222 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1223 
     | 
    
         
            +
                    };
         
     | 
| 
      
 1224 
     | 
    
         
            +
                    let onUnbindError = function () {
         
     | 
| 
      
 1225 
     | 
    
         
            +
                      unbindWebSocket();
         
     | 
| 
      
 1226 
     | 
    
         
            +
                      callbacks.error("Failed to destroy the server: Is the server down?");
         
     | 
| 
      
 1227 
     | 
    
         
            +
                      if (notifyDestroyed) gatewayCallbacks.destroyed();
         
     | 
| 
      
 1228 
     | 
    
         
            +
                    };
         
     | 
| 
      
 1229 
     | 
    
         
            +
                    ws.addEventListener('message', onUnbindMessage);
         
     | 
| 
      
 1230 
     | 
    
         
            +
                    ws.addEventListener('error', onUnbindError);
         
     | 
| 
      
 1231 
     | 
    
         
            +
                    if (ws.readyState === 1) {
         
     | 
| 
      
 1232 
     | 
    
         
            +
                      ws.send(JSON.stringify(request));
         
     | 
| 
      
 1233 
     | 
    
         
            +
                    } else {
         
     | 
| 
      
 1234 
     | 
    
         
            +
                      onUnbindError();
         
     | 
| 
      
 1235 
     | 
    
         
            +
                    }
         
     | 
| 
      
 1236 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 1237 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1238 
     | 
    
         
            +
                  Janus.httpAPICall(server + "/" + sessionId, {
         
     | 
| 
      
 1239 
     | 
    
         
            +
                    verb: 'POST',
         
     | 
| 
      
 1240 
     | 
    
         
            +
                    withCredentials: withCredentials,
         
     | 
| 
      
 1241 
     | 
    
         
            +
                    body: request,
         
     | 
| 
      
 1242 
     | 
    
         
            +
                    success: function (json) {
         
     | 
| 
      
 1243 
     | 
    
         
            +
                      Janus.log("Destroyed session:");
         
     | 
| 
      
 1244 
     | 
    
         
            +
                      Janus.debug(json);
         
     | 
| 
      
 1245 
     | 
    
         
            +
                      sessionId = null;
         
     | 
| 
      
 1246 
     | 
    
         
            +
                      connected = false;
         
     | 
| 
      
 1247 
     | 
    
         
            +
                      if (json["janus"] !== "success") {
         
     | 
| 
      
 1248 
     | 
    
         
            +
                        Janus.error("Ooops: " + json["error"].code + " " + json["error"].reason); // FIXME
         
     | 
| 
      
 1249 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1250 
     | 
    
         
            +
                      callbacks.success();
         
     | 
| 
      
 1251 
     | 
    
         
            +
                      if (notifyDestroyed) gatewayCallbacks.destroyed();
         
     | 
| 
      
 1252 
     | 
    
         
            +
                    },
         
     | 
| 
      
 1253 
     | 
    
         
            +
                    error: function (textStatus, errorThrown) {
         
     | 
| 
      
 1254 
     | 
    
         
            +
                      Janus.error(textStatus + ":", errorThrown); // FIXME
         
     | 
| 
      
 1255 
     | 
    
         
            +
                      // Reset everything anyway
         
     | 
| 
      
 1256 
     | 
    
         
            +
                      sessionId = null;
         
     | 
| 
      
 1257 
     | 
    
         
            +
                      connected = false;
         
     | 
| 
      
 1258 
     | 
    
         
            +
                      callbacks.success();
         
     | 
| 
      
 1259 
     | 
    
         
            +
                      if (notifyDestroyed) gatewayCallbacks.destroyed();
         
     | 
| 
      
 1260 
     | 
    
         
            +
                    }
         
     | 
| 
      
 1261 
     | 
    
         
            +
                  });
         
     | 
| 
      
 1262 
     | 
    
         
            +
                }
         
     | 
| 
      
 1263 
     | 
    
         
            +
             
     | 
| 
      
 1264 
     | 
    
         
            +
                // Private method to create a plugin handle
         
     | 
| 
      
 1265 
     | 
    
         
            +
                function createHandle(callbacks) {
         
     | 
| 
      
 1266 
     | 
    
         
            +
                  callbacks = callbacks || {};
         
     | 
| 
      
 1267 
     | 
    
         
            +
                  callbacks.success = typeof callbacks.success == "function" ? callbacks.success : Janus.noop;
         
     | 
| 
      
 1268 
     | 
    
         
            +
                  callbacks.error = typeof callbacks.error == "function" ? callbacks.error : Janus.noop;
         
     | 
| 
      
 1269 
     | 
    
         
            +
                  callbacks.dataChannelOptions = callbacks.dataChannelOptions || {
         
     | 
| 
      
 1270 
     | 
    
         
            +
                    ordered: true
         
     | 
| 
      
 1271 
     | 
    
         
            +
                  };
         
     | 
| 
      
 1272 
     | 
    
         
            +
                  callbacks.consentDialog = typeof callbacks.consentDialog == "function" ? callbacks.consentDialog : Janus.noop;
         
     | 
| 
      
 1273 
     | 
    
         
            +
                  callbacks.connectionState = typeof callbacks.connectionState == "function" ? callbacks.connectionState : Janus.noop;
         
     | 
| 
      
 1274 
     | 
    
         
            +
                  callbacks.iceState = typeof callbacks.iceState == "function" ? callbacks.iceState : Janus.noop;
         
     | 
| 
      
 1275 
     | 
    
         
            +
                  callbacks.mediaState = typeof callbacks.mediaState == "function" ? callbacks.mediaState : Janus.noop;
         
     | 
| 
      
 1276 
     | 
    
         
            +
                  callbacks.webrtcState = typeof callbacks.webrtcState == "function" ? callbacks.webrtcState : Janus.noop;
         
     | 
| 
      
 1277 
     | 
    
         
            +
                  callbacks.slowLink = typeof callbacks.slowLink == "function" ? callbacks.slowLink : Janus.noop;
         
     | 
| 
      
 1278 
     | 
    
         
            +
                  callbacks.onmessage = typeof callbacks.onmessage == "function" ? callbacks.onmessage : Janus.noop;
         
     | 
| 
      
 1279 
     | 
    
         
            +
                  callbacks.onlocaltrack = typeof callbacks.onlocaltrack == "function" ? callbacks.onlocaltrack : Janus.noop;
         
     | 
| 
      
 1280 
     | 
    
         
            +
                  callbacks.onremotetrack = typeof callbacks.onremotetrack == "function" ? callbacks.onremotetrack : Janus.noop;
         
     | 
| 
      
 1281 
     | 
    
         
            +
                  callbacks.ondata = typeof callbacks.ondata == "function" ? callbacks.ondata : Janus.noop;
         
     | 
| 
      
 1282 
     | 
    
         
            +
                  callbacks.ondataopen = typeof callbacks.ondataopen == "function" ? callbacks.ondataopen : Janus.noop;
         
     | 
| 
      
 1283 
     | 
    
         
            +
                  callbacks.oncleanup = typeof callbacks.oncleanup == "function" ? callbacks.oncleanup : Janus.noop;
         
     | 
| 
      
 1284 
     | 
    
         
            +
                  callbacks.ondetached = typeof callbacks.ondetached == "function" ? callbacks.ondetached : Janus.noop;
         
     | 
| 
      
 1285 
     | 
    
         
            +
                  if (!connected) {
         
     | 
| 
      
 1286 
     | 
    
         
            +
                    Janus.warn("Is the server down? (connected=false)");
         
     | 
| 
      
 1287 
     | 
    
         
            +
                    callbacks.error("Is the server down? (connected=false)");
         
     | 
| 
      
 1288 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 1289 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1290 
     | 
    
         
            +
                  let plugin = callbacks.plugin;
         
     | 
| 
      
 1291 
     | 
    
         
            +
                  if (!plugin) {
         
     | 
| 
      
 1292 
     | 
    
         
            +
                    Janus.error("Invalid plugin");
         
     | 
| 
      
 1293 
     | 
    
         
            +
                    callbacks.error("Invalid plugin");
         
     | 
| 
      
 1294 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 1295 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1296 
     | 
    
         
            +
                  let opaqueId = callbacks.opaqueId;
         
     | 
| 
      
 1297 
     | 
    
         
            +
                  let loopIndex = callbacks.loopIndex;
         
     | 
| 
      
 1298 
     | 
    
         
            +
                  let handleToken = callbacks.token ? callbacks.token : token;
         
     | 
| 
      
 1299 
     | 
    
         
            +
                  let transaction = Janus.randomString(12);
         
     | 
| 
      
 1300 
     | 
    
         
            +
                  let request = {
         
     | 
| 
      
 1301 
     | 
    
         
            +
                    "janus": "attach",
         
     | 
| 
      
 1302 
     | 
    
         
            +
                    "plugin": plugin,
         
     | 
| 
      
 1303 
     | 
    
         
            +
                    "opaque_id": opaqueId,
         
     | 
| 
      
 1304 
     | 
    
         
            +
                    "loop_index": loopIndex,
         
     | 
| 
      
 1305 
     | 
    
         
            +
                    "transaction": transaction
         
     | 
| 
      
 1306 
     | 
    
         
            +
                  };
         
     | 
| 
      
 1307 
     | 
    
         
            +
                  if (handleToken) request["token"] = handleToken;
         
     | 
| 
      
 1308 
     | 
    
         
            +
                  if (apisecret) request["apisecret"] = apisecret;
         
     | 
| 
      
 1309 
     | 
    
         
            +
                  if (websockets) {
         
     | 
| 
      
 1310 
     | 
    
         
            +
                    transactions.set(transaction, function (json) {
         
     | 
| 
      
 1311 
     | 
    
         
            +
                      Janus.debug(json);
         
     | 
| 
      
 1312 
     | 
    
         
            +
                      if (json["janus"] !== "success") {
         
     | 
| 
      
 1313 
     | 
    
         
            +
                        Janus.error("Ooops: " + json["error"].code + " " + json["error"].reason); // FIXME
         
     | 
| 
      
 1314 
     | 
    
         
            +
                        callbacks.error("Ooops: " + json["error"].code + " " + json["error"].reason);
         
     | 
| 
      
 1315 
     | 
    
         
            +
                        return;
         
     | 
| 
      
 1316 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1317 
     | 
    
         
            +
                      let handleId = json.data["id"];
         
     | 
| 
      
 1318 
     | 
    
         
            +
                      Janus.log("Created handle: " + handleId);
         
     | 
| 
      
 1319 
     | 
    
         
            +
                      let pluginHandle = {
         
     | 
| 
      
 1320 
     | 
    
         
            +
                        session: that,
         
     | 
| 
      
 1321 
     | 
    
         
            +
                        plugin: plugin,
         
     | 
| 
      
 1322 
     | 
    
         
            +
                        id: handleId,
         
     | 
| 
      
 1323 
     | 
    
         
            +
                        token: handleToken,
         
     | 
| 
      
 1324 
     | 
    
         
            +
                        detached: false,
         
     | 
| 
      
 1325 
     | 
    
         
            +
                        webrtcStuff: {
         
     | 
| 
      
 1326 
     | 
    
         
            +
                          started: false,
         
     | 
| 
      
 1327 
     | 
    
         
            +
                          myStream: null,
         
     | 
| 
      
 1328 
     | 
    
         
            +
                          streamExternal: false,
         
     | 
| 
      
 1329 
     | 
    
         
            +
                          mySdp: null,
         
     | 
| 
      
 1330 
     | 
    
         
            +
                          mediaConstraints: null,
         
     | 
| 
      
 1331 
     | 
    
         
            +
                          pc: null,
         
     | 
| 
      
 1332 
     | 
    
         
            +
                          dataChannelOptions: callbacks.dataChannelOptions,
         
     | 
| 
      
 1333 
     | 
    
         
            +
                          dataChannel: {},
         
     | 
| 
      
 1334 
     | 
    
         
            +
                          dtmfSender: null,
         
     | 
| 
      
 1335 
     | 
    
         
            +
                          trickle: true,
         
     | 
| 
      
 1336 
     | 
    
         
            +
                          iceDone: false,
         
     | 
| 
      
 1337 
     | 
    
         
            +
                          bitrate: {}
         
     | 
| 
      
 1338 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1339 
     | 
    
         
            +
                        getId: function () {
         
     | 
| 
      
 1340 
     | 
    
         
            +
                          return handleId;
         
     | 
| 
      
 1341 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1342 
     | 
    
         
            +
                        getPlugin: function () {
         
     | 
| 
      
 1343 
     | 
    
         
            +
                          return plugin;
         
     | 
| 
      
 1344 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1345 
     | 
    
         
            +
                        getVolume: function (mid, result) {
         
     | 
| 
      
 1346 
     | 
    
         
            +
                          return getVolume(handleId, mid, true, result);
         
     | 
| 
      
 1347 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1348 
     | 
    
         
            +
                        getRemoteVolume: function (mid, result) {
         
     | 
| 
      
 1349 
     | 
    
         
            +
                          return getVolume(handleId, mid, true, result);
         
     | 
| 
      
 1350 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1351 
     | 
    
         
            +
                        getLocalVolume: function (mid, result) {
         
     | 
| 
      
 1352 
     | 
    
         
            +
                          return getVolume(handleId, mid, false, result);
         
     | 
| 
      
 1353 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1354 
     | 
    
         
            +
                        isAudioMuted: function (mid) {
         
     | 
| 
      
 1355 
     | 
    
         
            +
                          return isMuted(handleId, mid, false);
         
     | 
| 
      
 1356 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1357 
     | 
    
         
            +
                        muteAudio: function (mid) {
         
     | 
| 
      
 1358 
     | 
    
         
            +
                          return mute(handleId, mid, false, true);
         
     | 
| 
      
 1359 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1360 
     | 
    
         
            +
                        unmuteAudio: function (mid) {
         
     | 
| 
      
 1361 
     | 
    
         
            +
                          return mute(handleId, mid, false, false);
         
     | 
| 
      
 1362 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1363 
     | 
    
         
            +
                        isVideoMuted: function (mid) {
         
     | 
| 
      
 1364 
     | 
    
         
            +
                          return isMuted(handleId, mid, true);
         
     | 
| 
      
 1365 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1366 
     | 
    
         
            +
                        muteVideo: function (mid) {
         
     | 
| 
      
 1367 
     | 
    
         
            +
                          return mute(handleId, mid, true, true);
         
     | 
| 
      
 1368 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1369 
     | 
    
         
            +
                        unmuteVideo: function (mid) {
         
     | 
| 
      
 1370 
     | 
    
         
            +
                          return mute(handleId, mid, true, false);
         
     | 
| 
      
 1371 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1372 
     | 
    
         
            +
                        getBitrate: function (mid) {
         
     | 
| 
      
 1373 
     | 
    
         
            +
                          return getBitrate(handleId, mid);
         
     | 
| 
      
 1374 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1375 
     | 
    
         
            +
                        setMaxBitrate: function (mid, bitrate) {
         
     | 
| 
      
 1376 
     | 
    
         
            +
                          return setBitrate(handleId, mid, bitrate);
         
     | 
| 
      
 1377 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1378 
     | 
    
         
            +
                        send: function (callbacks) {
         
     | 
| 
      
 1379 
     | 
    
         
            +
                          sendMessage(handleId, callbacks);
         
     | 
| 
      
 1380 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1381 
     | 
    
         
            +
                        data: function (callbacks) {
         
     | 
| 
      
 1382 
     | 
    
         
            +
                          sendData(handleId, callbacks);
         
     | 
| 
      
 1383 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1384 
     | 
    
         
            +
                        dtmf: function (callbacks) {
         
     | 
| 
      
 1385 
     | 
    
         
            +
                          sendDtmf(handleId, callbacks);
         
     | 
| 
      
 1386 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1387 
     | 
    
         
            +
                        consentDialog: callbacks.consentDialog,
         
     | 
| 
      
 1388 
     | 
    
         
            +
                        connectionState: callbacks.connectionState,
         
     | 
| 
      
 1389 
     | 
    
         
            +
                        iceState: callbacks.iceState,
         
     | 
| 
      
 1390 
     | 
    
         
            +
                        mediaState: callbacks.mediaState,
         
     | 
| 
      
 1391 
     | 
    
         
            +
                        webrtcState: callbacks.webrtcState,
         
     | 
| 
      
 1392 
     | 
    
         
            +
                        slowLink: callbacks.slowLink,
         
     | 
| 
      
 1393 
     | 
    
         
            +
                        onmessage: callbacks.onmessage,
         
     | 
| 
      
 1394 
     | 
    
         
            +
                        createOffer: function (callbacks) {
         
     | 
| 
      
 1395 
     | 
    
         
            +
                          prepareWebrtc(handleId, true, callbacks);
         
     | 
| 
      
 1396 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1397 
     | 
    
         
            +
                        createAnswer: function (callbacks) {
         
     | 
| 
      
 1398 
     | 
    
         
            +
                          prepareWebrtc(handleId, false, callbacks);
         
     | 
| 
      
 1399 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1400 
     | 
    
         
            +
                        handleRemoteJsep: function (callbacks) {
         
     | 
| 
      
 1401 
     | 
    
         
            +
                          prepareWebrtcPeer(handleId, callbacks);
         
     | 
| 
      
 1402 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1403 
     | 
    
         
            +
                        replaceTracks: function (callbacks) {
         
     | 
| 
      
 1404 
     | 
    
         
            +
                          replaceTracks(handleId, callbacks);
         
     | 
| 
      
 1405 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1406 
     | 
    
         
            +
                        getLocalTracks: function () {
         
     | 
| 
      
 1407 
     | 
    
         
            +
                          return getLocalTracks(handleId);
         
     | 
| 
      
 1408 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1409 
     | 
    
         
            +
                        getRemoteTracks: function () {
         
     | 
| 
      
 1410 
     | 
    
         
            +
                          return getRemoteTracks(handleId);
         
     | 
| 
      
 1411 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1412 
     | 
    
         
            +
                        onlocaltrack: callbacks.onlocaltrack,
         
     | 
| 
      
 1413 
     | 
    
         
            +
                        onremotetrack: callbacks.onremotetrack,
         
     | 
| 
      
 1414 
     | 
    
         
            +
                        ondata: callbacks.ondata,
         
     | 
| 
      
 1415 
     | 
    
         
            +
                        ondataopen: callbacks.ondataopen,
         
     | 
| 
      
 1416 
     | 
    
         
            +
                        oncleanup: callbacks.oncleanup,
         
     | 
| 
      
 1417 
     | 
    
         
            +
                        ondetached: callbacks.ondetached,
         
     | 
| 
      
 1418 
     | 
    
         
            +
                        hangup: function (sendRequest) {
         
     | 
| 
      
 1419 
     | 
    
         
            +
                          cleanupWebrtc(handleId, sendRequest === true);
         
     | 
| 
      
 1420 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1421 
     | 
    
         
            +
                        detach: function (callbacks) {
         
     | 
| 
      
 1422 
     | 
    
         
            +
                          destroyHandle(handleId, callbacks);
         
     | 
| 
      
 1423 
     | 
    
         
            +
                        }
         
     | 
| 
      
 1424 
     | 
    
         
            +
                      };
         
     | 
| 
      
 1425 
     | 
    
         
            +
                      pluginHandles.set(handleId, pluginHandle);
         
     | 
| 
      
 1426 
     | 
    
         
            +
                      callbacks.success(pluginHandle);
         
     | 
| 
      
 1427 
     | 
    
         
            +
                    });
         
     | 
| 
      
 1428 
     | 
    
         
            +
                    request["session_id"] = sessionId;
         
     | 
| 
      
 1429 
     | 
    
         
            +
                    ws.send(JSON.stringify(request));
         
     | 
| 
      
 1430 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 1431 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1432 
     | 
    
         
            +
                  Janus.httpAPICall(server + "/" + sessionId, {
         
     | 
| 
      
 1433 
     | 
    
         
            +
                    verb: 'POST',
         
     | 
| 
      
 1434 
     | 
    
         
            +
                    withCredentials: withCredentials,
         
     | 
| 
      
 1435 
     | 
    
         
            +
                    body: request,
         
     | 
| 
      
 1436 
     | 
    
         
            +
                    success: function (json) {
         
     | 
| 
      
 1437 
     | 
    
         
            +
                      Janus.debug(json);
         
     | 
| 
      
 1438 
     | 
    
         
            +
                      if (json["janus"] !== "success") {
         
     | 
| 
      
 1439 
     | 
    
         
            +
                        Janus.error("Ooops: " + json["error"].code + " " + json["error"].reason); // FIXME
         
     | 
| 
      
 1440 
     | 
    
         
            +
                        callbacks.error("Ooops: " + json["error"].code + " " + json["error"].reason);
         
     | 
| 
      
 1441 
     | 
    
         
            +
                        return;
         
     | 
| 
      
 1442 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1443 
     | 
    
         
            +
                      let handleId = json.data["id"];
         
     | 
| 
      
 1444 
     | 
    
         
            +
                      Janus.log("Created handle: " + handleId);
         
     | 
| 
      
 1445 
     | 
    
         
            +
                      let pluginHandle = {
         
     | 
| 
      
 1446 
     | 
    
         
            +
                        session: that,
         
     | 
| 
      
 1447 
     | 
    
         
            +
                        plugin: plugin,
         
     | 
| 
      
 1448 
     | 
    
         
            +
                        id: handleId,
         
     | 
| 
      
 1449 
     | 
    
         
            +
                        token: handleToken,
         
     | 
| 
      
 1450 
     | 
    
         
            +
                        detached: false,
         
     | 
| 
      
 1451 
     | 
    
         
            +
                        webrtcStuff: {
         
     | 
| 
      
 1452 
     | 
    
         
            +
                          started: false,
         
     | 
| 
      
 1453 
     | 
    
         
            +
                          myStream: null,
         
     | 
| 
      
 1454 
     | 
    
         
            +
                          streamExternal: false,
         
     | 
| 
      
 1455 
     | 
    
         
            +
                          mySdp: null,
         
     | 
| 
      
 1456 
     | 
    
         
            +
                          mediaConstraints: null,
         
     | 
| 
      
 1457 
     | 
    
         
            +
                          pc: null,
         
     | 
| 
      
 1458 
     | 
    
         
            +
                          dataChannelOptions: callbacks.dataChannelOptions,
         
     | 
| 
      
 1459 
     | 
    
         
            +
                          dataChannel: {},
         
     | 
| 
      
 1460 
     | 
    
         
            +
                          dtmfSender: null,
         
     | 
| 
      
 1461 
     | 
    
         
            +
                          trickle: true,
         
     | 
| 
      
 1462 
     | 
    
         
            +
                          iceDone: false,
         
     | 
| 
      
 1463 
     | 
    
         
            +
                          bitrate: {}
         
     | 
| 
      
 1464 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1465 
     | 
    
         
            +
                        getId: function () {
         
     | 
| 
      
 1466 
     | 
    
         
            +
                          return handleId;
         
     | 
| 
      
 1467 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1468 
     | 
    
         
            +
                        getPlugin: function () {
         
     | 
| 
      
 1469 
     | 
    
         
            +
                          return plugin;
         
     | 
| 
      
 1470 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1471 
     | 
    
         
            +
                        getVolume: function (mid, result) {
         
     | 
| 
      
 1472 
     | 
    
         
            +
                          return getVolume(handleId, mid, true, result);
         
     | 
| 
      
 1473 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1474 
     | 
    
         
            +
                        getRemoteVolume: function (mid, result) {
         
     | 
| 
      
 1475 
     | 
    
         
            +
                          return getVolume(handleId, mid, true, result);
         
     | 
| 
      
 1476 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1477 
     | 
    
         
            +
                        getLocalVolume: function (mid, result) {
         
     | 
| 
      
 1478 
     | 
    
         
            +
                          return getVolume(handleId, mid, false, result);
         
     | 
| 
      
 1479 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1480 
     | 
    
         
            +
                        isAudioMuted: function (mid) {
         
     | 
| 
      
 1481 
     | 
    
         
            +
                          return isMuted(handleId, mid, false);
         
     | 
| 
      
 1482 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1483 
     | 
    
         
            +
                        muteAudio: function (mid) {
         
     | 
| 
      
 1484 
     | 
    
         
            +
                          return mute(handleId, mid, false, true);
         
     | 
| 
      
 1485 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1486 
     | 
    
         
            +
                        unmuteAudio: function (mid) {
         
     | 
| 
      
 1487 
     | 
    
         
            +
                          return mute(handleId, mid, false, false);
         
     | 
| 
      
 1488 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1489 
     | 
    
         
            +
                        isVideoMuted: function (mid) {
         
     | 
| 
      
 1490 
     | 
    
         
            +
                          return isMuted(handleId, mid, true);
         
     | 
| 
      
 1491 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1492 
     | 
    
         
            +
                        muteVideo: function (mid) {
         
     | 
| 
      
 1493 
     | 
    
         
            +
                          return mute(handleId, mid, true, true);
         
     | 
| 
      
 1494 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1495 
     | 
    
         
            +
                        unmuteVideo: function (mid) {
         
     | 
| 
      
 1496 
     | 
    
         
            +
                          return mute(handleId, mid, true, false);
         
     | 
| 
      
 1497 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1498 
     | 
    
         
            +
                        getBitrate: function (mid) {
         
     | 
| 
      
 1499 
     | 
    
         
            +
                          return getBitrate(handleId, mid);
         
     | 
| 
      
 1500 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1501 
     | 
    
         
            +
                        setMaxBitrate: function (mid, bitrate) {
         
     | 
| 
      
 1502 
     | 
    
         
            +
                          return setBitrate(handleId, mid, bitrate);
         
     | 
| 
      
 1503 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1504 
     | 
    
         
            +
                        send: function (callbacks) {
         
     | 
| 
      
 1505 
     | 
    
         
            +
                          sendMessage(handleId, callbacks);
         
     | 
| 
      
 1506 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1507 
     | 
    
         
            +
                        data: function (callbacks) {
         
     | 
| 
      
 1508 
     | 
    
         
            +
                          sendData(handleId, callbacks);
         
     | 
| 
      
 1509 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1510 
     | 
    
         
            +
                        dtmf: function (callbacks) {
         
     | 
| 
      
 1511 
     | 
    
         
            +
                          sendDtmf(handleId, callbacks);
         
     | 
| 
      
 1512 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1513 
     | 
    
         
            +
                        consentDialog: callbacks.consentDialog,
         
     | 
| 
      
 1514 
     | 
    
         
            +
                        connectionState: callbacks.connectionState,
         
     | 
| 
      
 1515 
     | 
    
         
            +
                        iceState: callbacks.iceState,
         
     | 
| 
      
 1516 
     | 
    
         
            +
                        mediaState: callbacks.mediaState,
         
     | 
| 
      
 1517 
     | 
    
         
            +
                        webrtcState: callbacks.webrtcState,
         
     | 
| 
      
 1518 
     | 
    
         
            +
                        slowLink: callbacks.slowLink,
         
     | 
| 
      
 1519 
     | 
    
         
            +
                        onmessage: callbacks.onmessage,
         
     | 
| 
      
 1520 
     | 
    
         
            +
                        createOffer: function (callbacks) {
         
     | 
| 
      
 1521 
     | 
    
         
            +
                          prepareWebrtc(handleId, true, callbacks);
         
     | 
| 
      
 1522 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1523 
     | 
    
         
            +
                        createAnswer: function (callbacks) {
         
     | 
| 
      
 1524 
     | 
    
         
            +
                          prepareWebrtc(handleId, false, callbacks);
         
     | 
| 
      
 1525 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1526 
     | 
    
         
            +
                        handleRemoteJsep: function (callbacks) {
         
     | 
| 
      
 1527 
     | 
    
         
            +
                          prepareWebrtcPeer(handleId, callbacks);
         
     | 
| 
      
 1528 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1529 
     | 
    
         
            +
                        replaceTracks: function (callbacks) {
         
     | 
| 
      
 1530 
     | 
    
         
            +
                          replaceTracks(handleId, callbacks);
         
     | 
| 
      
 1531 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1532 
     | 
    
         
            +
                        getLocalTracks: function () {
         
     | 
| 
      
 1533 
     | 
    
         
            +
                          return getLocalTracks(handleId);
         
     | 
| 
      
 1534 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1535 
     | 
    
         
            +
                        getRemoteTracks: function () {
         
     | 
| 
      
 1536 
     | 
    
         
            +
                          return getRemoteTracks(handleId);
         
     | 
| 
      
 1537 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1538 
     | 
    
         
            +
                        onlocaltrack: callbacks.onlocaltrack,
         
     | 
| 
      
 1539 
     | 
    
         
            +
                        onremotetrack: callbacks.onremotetrack,
         
     | 
| 
      
 1540 
     | 
    
         
            +
                        ondata: callbacks.ondata,
         
     | 
| 
      
 1541 
     | 
    
         
            +
                        ondataopen: callbacks.ondataopen,
         
     | 
| 
      
 1542 
     | 
    
         
            +
                        oncleanup: callbacks.oncleanup,
         
     | 
| 
      
 1543 
     | 
    
         
            +
                        ondetached: callbacks.ondetached,
         
     | 
| 
      
 1544 
     | 
    
         
            +
                        hangup: function (sendRequest) {
         
     | 
| 
      
 1545 
     | 
    
         
            +
                          cleanupWebrtc(handleId, sendRequest === true);
         
     | 
| 
      
 1546 
     | 
    
         
            +
                        },
         
     | 
| 
      
 1547 
     | 
    
         
            +
                        detach: function (callbacks) {
         
     | 
| 
      
 1548 
     | 
    
         
            +
                          destroyHandle(handleId, callbacks);
         
     | 
| 
      
 1549 
     | 
    
         
            +
                        }
         
     | 
| 
      
 1550 
     | 
    
         
            +
                      };
         
     | 
| 
      
 1551 
     | 
    
         
            +
                      pluginHandles.set(handleId, pluginHandle);
         
     | 
| 
      
 1552 
     | 
    
         
            +
                      callbacks.success(pluginHandle);
         
     | 
| 
      
 1553 
     | 
    
         
            +
                    },
         
     | 
| 
      
 1554 
     | 
    
         
            +
                    error: function (textStatus, errorThrown) {
         
     | 
| 
      
 1555 
     | 
    
         
            +
                      Janus.error(textStatus + ":", errorThrown); // FIXME
         
     | 
| 
      
 1556 
     | 
    
         
            +
                      if (errorThrown === "") callbacks.error(textStatus + ": Is the server down?");else callbacks.error(textStatus + ": " + errorThrown);
         
     | 
| 
      
 1557 
     | 
    
         
            +
                    }
         
     | 
| 
      
 1558 
     | 
    
         
            +
                  });
         
     | 
| 
      
 1559 
     | 
    
         
            +
                }
         
     | 
| 
      
 1560 
     | 
    
         
            +
             
     | 
| 
      
 1561 
     | 
    
         
            +
                // Private method to send a message
         
     | 
| 
      
 1562 
     | 
    
         
            +
                function sendMessage(handleId, callbacks) {
         
     | 
| 
      
 1563 
     | 
    
         
            +
                  callbacks = callbacks || {};
         
     | 
| 
      
 1564 
     | 
    
         
            +
                  callbacks.success = typeof callbacks.success == "function" ? callbacks.success : Janus.noop;
         
     | 
| 
      
 1565 
     | 
    
         
            +
                  callbacks.error = typeof callbacks.error == "function" ? callbacks.error : Janus.noop;
         
     | 
| 
      
 1566 
     | 
    
         
            +
                  if (!connected) {
         
     | 
| 
      
 1567 
     | 
    
         
            +
                    Janus.warn("Is the server down? (connected=false)");
         
     | 
| 
      
 1568 
     | 
    
         
            +
                    callbacks.error("Is the server down? (connected=false)");
         
     | 
| 
      
 1569 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 1570 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1571 
     | 
    
         
            +
                  let pluginHandle = pluginHandles.get(handleId);
         
     | 
| 
      
 1572 
     | 
    
         
            +
                  if (!pluginHandle || !pluginHandle.webrtcStuff) {
         
     | 
| 
      
 1573 
     | 
    
         
            +
                    Janus.warn("Invalid handle");
         
     | 
| 
      
 1574 
     | 
    
         
            +
                    callbacks.error("Invalid handle");
         
     | 
| 
      
 1575 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 1576 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1577 
     | 
    
         
            +
                  let message = callbacks.message;
         
     | 
| 
      
 1578 
     | 
    
         
            +
                  let jsep = callbacks.jsep;
         
     | 
| 
      
 1579 
     | 
    
         
            +
                  let transaction = Janus.randomString(12);
         
     | 
| 
      
 1580 
     | 
    
         
            +
                  let request = {
         
     | 
| 
      
 1581 
     | 
    
         
            +
                    "janus": "message",
         
     | 
| 
      
 1582 
     | 
    
         
            +
                    "body": message,
         
     | 
| 
      
 1583 
     | 
    
         
            +
                    "transaction": transaction
         
     | 
| 
      
 1584 
     | 
    
         
            +
                  };
         
     | 
| 
      
 1585 
     | 
    
         
            +
                  if (pluginHandle.token) request["token"] = pluginHandle.token;
         
     | 
| 
      
 1586 
     | 
    
         
            +
                  if (apisecret) request["apisecret"] = apisecret;
         
     | 
| 
      
 1587 
     | 
    
         
            +
                  if (jsep) {
         
     | 
| 
      
 1588 
     | 
    
         
            +
                    request.jsep = {
         
     | 
| 
      
 1589 
     | 
    
         
            +
                      type: jsep.type,
         
     | 
| 
      
 1590 
     | 
    
         
            +
                      sdp: jsep.sdp
         
     | 
| 
      
 1591 
     | 
    
         
            +
                    };
         
     | 
| 
      
 1592 
     | 
    
         
            +
                    if (jsep.e2ee) request.jsep.e2ee = true;
         
     | 
| 
      
 1593 
     | 
    
         
            +
                    if (jsep.rid_order === "hml" || jsep.rid_order === "lmh") request.jsep.rid_order = jsep.rid_order;
         
     | 
| 
      
 1594 
     | 
    
         
            +
                    if (jsep.force_relay) request.jsep.force_relay = true;
         
     | 
| 
      
 1595 
     | 
    
         
            +
                    // Check if there's SVC video streams to tell Janus about
         
     | 
| 
      
 1596 
     | 
    
         
            +
                    let svc = null;
         
     | 
| 
      
 1597 
     | 
    
         
            +
                    let config = pluginHandle.webrtcStuff;
         
     | 
| 
      
 1598 
     | 
    
         
            +
                    if (config.pc) {
         
     | 
| 
      
 1599 
     | 
    
         
            +
                      let transceivers = config.pc.getTransceivers();
         
     | 
| 
      
 1600 
     | 
    
         
            +
                      if (transceivers && transceivers.length > 0) {
         
     | 
| 
      
 1601 
     | 
    
         
            +
                        for (let mindex in transceivers) {
         
     | 
| 
      
 1602 
     | 
    
         
            +
                          let tr = transceivers[mindex];
         
     | 
| 
      
 1603 
     | 
    
         
            +
                          if (tr && tr.sender && tr.sender.track && tr.sender.track.kind === 'video') {
         
     | 
| 
      
 1604 
     | 
    
         
            +
                            let params = tr.sender.getParameters();
         
     | 
| 
      
 1605 
     | 
    
         
            +
                            if (params && params.encodings && params.encodings[0] && params.encodings[0].scalabilityMode) {
         
     | 
| 
      
 1606 
     | 
    
         
            +
                              // This video stream uses SVC
         
     | 
| 
      
 1607 
     | 
    
         
            +
                              if (!svc) svc = [];
         
     | 
| 
      
 1608 
     | 
    
         
            +
                              svc.push({
         
     | 
| 
      
 1609 
     | 
    
         
            +
                                mindex: parseInt(mindex),
         
     | 
| 
      
 1610 
     | 
    
         
            +
                                mid: tr.mid,
         
     | 
| 
      
 1611 
     | 
    
         
            +
                                svc: params.encodings[0].scalabilityMode
         
     | 
| 
      
 1612 
     | 
    
         
            +
                              });
         
     | 
| 
      
 1613 
     | 
    
         
            +
                            }
         
     | 
| 
      
 1614 
     | 
    
         
            +
                          }
         
     | 
| 
      
 1615 
     | 
    
         
            +
                        }
         
     | 
| 
      
 1616 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1617 
     | 
    
         
            +
                    }
         
     | 
| 
      
 1618 
     | 
    
         
            +
                    if (svc) request.jsep.svc = svc;
         
     | 
| 
      
 1619 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1620 
     | 
    
         
            +
                  Janus.debug("Sending message to plugin (handle=" + handleId + "):");
         
     | 
| 
      
 1621 
     | 
    
         
            +
                  Janus.debug(request);
         
     | 
| 
      
 1622 
     | 
    
         
            +
                  if (websockets) {
         
     | 
| 
      
 1623 
     | 
    
         
            +
                    request["session_id"] = sessionId;
         
     | 
| 
      
 1624 
     | 
    
         
            +
                    request["handle_id"] = handleId;
         
     | 
| 
      
 1625 
     | 
    
         
            +
                    transactions.set(transaction, function (json) {
         
     | 
| 
      
 1626 
     | 
    
         
            +
                      Janus.debug("Message sent!");
         
     | 
| 
      
 1627 
     | 
    
         
            +
                      Janus.debug(json);
         
     | 
| 
      
 1628 
     | 
    
         
            +
                      if (json["janus"] === "success") {
         
     | 
| 
      
 1629 
     | 
    
         
            +
                        // We got a success, must have been a synchronous transaction
         
     | 
| 
      
 1630 
     | 
    
         
            +
                        let plugindata = json["plugindata"];
         
     | 
| 
      
 1631 
     | 
    
         
            +
                        if (!plugindata) {
         
     | 
| 
      
 1632 
     | 
    
         
            +
                          Janus.warn("Request succeeded, but missing plugindata...");
         
     | 
| 
      
 1633 
     | 
    
         
            +
                          callbacks.success();
         
     | 
| 
      
 1634 
     | 
    
         
            +
                          return;
         
     | 
| 
      
 1635 
     | 
    
         
            +
                        }
         
     | 
| 
      
 1636 
     | 
    
         
            +
                        Janus.log("Synchronous transaction successful (" + plugindata["plugin"] + ")");
         
     | 
| 
      
 1637 
     | 
    
         
            +
                        let data = plugindata["data"];
         
     | 
| 
      
 1638 
     | 
    
         
            +
                        Janus.debug(data);
         
     | 
| 
      
 1639 
     | 
    
         
            +
                        callbacks.success(data);
         
     | 
| 
      
 1640 
     | 
    
         
            +
                        return;
         
     | 
| 
      
 1641 
     | 
    
         
            +
                      } else if (json["janus"] !== "ack") {
         
     | 
| 
      
 1642 
     | 
    
         
            +
                        // Not a success and not an ack, must be an error
         
     | 
| 
      
 1643 
     | 
    
         
            +
                        if (json["error"]) {
         
     | 
| 
      
 1644 
     | 
    
         
            +
                          Janus.error("Ooops: " + json["error"].code + " " + json["error"].reason); // FIXME
         
     | 
| 
      
 1645 
     | 
    
         
            +
                          callbacks.error(json["error"].code + " " + json["error"].reason);
         
     | 
| 
      
 1646 
     | 
    
         
            +
                        } else {
         
     | 
| 
      
 1647 
     | 
    
         
            +
                          Janus.error("Unknown error"); // FIXME
         
     | 
| 
      
 1648 
     | 
    
         
            +
                          callbacks.error("Unknown error");
         
     | 
| 
      
 1649 
     | 
    
         
            +
                        }
         
     | 
| 
      
 1650 
     | 
    
         
            +
                        return;
         
     | 
| 
      
 1651 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1652 
     | 
    
         
            +
                      // If we got here, the plugin decided to handle the request asynchronously
         
     | 
| 
      
 1653 
     | 
    
         
            +
                      callbacks.success();
         
     | 
| 
      
 1654 
     | 
    
         
            +
                    });
         
     | 
| 
      
 1655 
     | 
    
         
            +
                    ws.send(JSON.stringify(request));
         
     | 
| 
      
 1656 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 1657 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1658 
     | 
    
         
            +
                  Janus.httpAPICall(server + "/" + sessionId + "/" + handleId, {
         
     | 
| 
      
 1659 
     | 
    
         
            +
                    verb: 'POST',
         
     | 
| 
      
 1660 
     | 
    
         
            +
                    withCredentials: withCredentials,
         
     | 
| 
      
 1661 
     | 
    
         
            +
                    body: request,
         
     | 
| 
      
 1662 
     | 
    
         
            +
                    success: function (json) {
         
     | 
| 
      
 1663 
     | 
    
         
            +
                      Janus.debug("Message sent!");
         
     | 
| 
      
 1664 
     | 
    
         
            +
                      Janus.debug(json);
         
     | 
| 
      
 1665 
     | 
    
         
            +
                      if (json["janus"] === "success") {
         
     | 
| 
      
 1666 
     | 
    
         
            +
                        // We got a success, must have been a synchronous transaction
         
     | 
| 
      
 1667 
     | 
    
         
            +
                        let plugindata = json["plugindata"];
         
     | 
| 
      
 1668 
     | 
    
         
            +
                        if (!plugindata) {
         
     | 
| 
      
 1669 
     | 
    
         
            +
                          Janus.warn("Request succeeded, but missing plugindata...");
         
     | 
| 
      
 1670 
     | 
    
         
            +
                          callbacks.success();
         
     | 
| 
      
 1671 
     | 
    
         
            +
                          return;
         
     | 
| 
      
 1672 
     | 
    
         
            +
                        }
         
     | 
| 
      
 1673 
     | 
    
         
            +
                        Janus.log("Synchronous transaction successful (" + plugindata["plugin"] + ")");
         
     | 
| 
      
 1674 
     | 
    
         
            +
                        let data = plugindata["data"];
         
     | 
| 
      
 1675 
     | 
    
         
            +
                        Janus.debug(data);
         
     | 
| 
      
 1676 
     | 
    
         
            +
                        callbacks.success(data);
         
     | 
| 
      
 1677 
     | 
    
         
            +
                        return;
         
     | 
| 
      
 1678 
     | 
    
         
            +
                      } else if (json["janus"] !== "ack") {
         
     | 
| 
      
 1679 
     | 
    
         
            +
                        // Not a success and not an ack, must be an error
         
     | 
| 
      
 1680 
     | 
    
         
            +
                        if (json["error"]) {
         
     | 
| 
      
 1681 
     | 
    
         
            +
                          Janus.error("Ooops: " + json["error"].code + " " + json["error"].reason); // FIXME
         
     | 
| 
      
 1682 
     | 
    
         
            +
                          callbacks.error(json["error"].code + " " + json["error"].reason);
         
     | 
| 
      
 1683 
     | 
    
         
            +
                        } else {
         
     | 
| 
      
 1684 
     | 
    
         
            +
                          Janus.error("Unknown error"); // FIXME
         
     | 
| 
      
 1685 
     | 
    
         
            +
                          callbacks.error("Unknown error");
         
     | 
| 
      
 1686 
     | 
    
         
            +
                        }
         
     | 
| 
      
 1687 
     | 
    
         
            +
                        return;
         
     | 
| 
      
 1688 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1689 
     | 
    
         
            +
                      // If we got here, the plugin decided to handle the request asynchronously
         
     | 
| 
      
 1690 
     | 
    
         
            +
                      callbacks.success();
         
     | 
| 
      
 1691 
     | 
    
         
            +
                    },
         
     | 
| 
      
 1692 
     | 
    
         
            +
                    error: function (textStatus, errorThrown) {
         
     | 
| 
      
 1693 
     | 
    
         
            +
                      Janus.error(textStatus + ":", errorThrown); // FIXME
         
     | 
| 
      
 1694 
     | 
    
         
            +
                      callbacks.error(textStatus + ": " + errorThrown);
         
     | 
| 
      
 1695 
     | 
    
         
            +
                    }
         
     | 
| 
      
 1696 
     | 
    
         
            +
                  });
         
     | 
| 
      
 1697 
     | 
    
         
            +
                }
         
     | 
| 
      
 1698 
     | 
    
         
            +
             
     | 
| 
      
 1699 
     | 
    
         
            +
                // Private method to send a trickle candidate
         
     | 
| 
      
 1700 
     | 
    
         
            +
                function sendTrickleCandidate(handleId, candidate) {
         
     | 
| 
      
 1701 
     | 
    
         
            +
                  if (!connected) {
         
     | 
| 
      
 1702 
     | 
    
         
            +
                    Janus.warn("Is the server down? (connected=false)");
         
     | 
| 
      
 1703 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 1704 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1705 
     | 
    
         
            +
                  let pluginHandle = pluginHandles.get(handleId);
         
     | 
| 
      
 1706 
     | 
    
         
            +
                  if (!pluginHandle || !pluginHandle.webrtcStuff) {
         
     | 
| 
      
 1707 
     | 
    
         
            +
                    Janus.warn("Invalid handle");
         
     | 
| 
      
 1708 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 1709 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1710 
     | 
    
         
            +
                  let request = {
         
     | 
| 
      
 1711 
     | 
    
         
            +
                    "janus": "trickle",
         
     | 
| 
      
 1712 
     | 
    
         
            +
                    "candidate": candidate,
         
     | 
| 
      
 1713 
     | 
    
         
            +
                    "transaction": Janus.randomString(12)
         
     | 
| 
      
 1714 
     | 
    
         
            +
                  };
         
     | 
| 
      
 1715 
     | 
    
         
            +
                  if (pluginHandle.token) request["token"] = pluginHandle.token;
         
     | 
| 
      
 1716 
     | 
    
         
            +
                  if (apisecret) request["apisecret"] = apisecret;
         
     | 
| 
      
 1717 
     | 
    
         
            +
                  Janus.vdebug("Sending trickle candidate (handle=" + handleId + "):");
         
     | 
| 
      
 1718 
     | 
    
         
            +
                  Janus.vdebug(request);
         
     | 
| 
      
 1719 
     | 
    
         
            +
                  if (websockets) {
         
     | 
| 
      
 1720 
     | 
    
         
            +
                    request["session_id"] = sessionId;
         
     | 
| 
      
 1721 
     | 
    
         
            +
                    request["handle_id"] = handleId;
         
     | 
| 
      
 1722 
     | 
    
         
            +
                    ws.send(JSON.stringify(request));
         
     | 
| 
      
 1723 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 1724 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1725 
     | 
    
         
            +
                  Janus.httpAPICall(server + "/" + sessionId + "/" + handleId, {
         
     | 
| 
      
 1726 
     | 
    
         
            +
                    verb: 'POST',
         
     | 
| 
      
 1727 
     | 
    
         
            +
                    withCredentials: withCredentials,
         
     | 
| 
      
 1728 
     | 
    
         
            +
                    body: request,
         
     | 
| 
      
 1729 
     | 
    
         
            +
                    success: function (json) {
         
     | 
| 
      
 1730 
     | 
    
         
            +
                      Janus.vdebug("Candidate sent!");
         
     | 
| 
      
 1731 
     | 
    
         
            +
                      Janus.vdebug(json);
         
     | 
| 
      
 1732 
     | 
    
         
            +
                      if (json["janus"] !== "ack") {
         
     | 
| 
      
 1733 
     | 
    
         
            +
                        Janus.error("Ooops: " + json["error"].code + " " + json["error"].reason); // FIXME
         
     | 
| 
      
 1734 
     | 
    
         
            +
                        return;
         
     | 
| 
      
 1735 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1736 
     | 
    
         
            +
                    },
         
     | 
| 
      
 1737 
     | 
    
         
            +
                    error: function (textStatus, errorThrown) {
         
     | 
| 
      
 1738 
     | 
    
         
            +
                      Janus.error(textStatus + ":", errorThrown); // FIXME
         
     | 
| 
      
 1739 
     | 
    
         
            +
                    }
         
     | 
| 
      
 1740 
     | 
    
         
            +
                  });
         
     | 
| 
      
 1741 
     | 
    
         
            +
                }
         
     | 
| 
      
 1742 
     | 
    
         
            +
             
     | 
| 
      
 1743 
     | 
    
         
            +
                // Private method to create a data channel
         
     | 
| 
      
 1744 
     | 
    
         
            +
                function createDataChannel(handleId, dclabel, dcprotocol, incoming, pendingData) {
         
     | 
| 
      
 1745 
     | 
    
         
            +
                  let pluginHandle = pluginHandles.get(handleId);
         
     | 
| 
      
 1746 
     | 
    
         
            +
                  if (!pluginHandle || !pluginHandle.webrtcStuff) {
         
     | 
| 
      
 1747 
     | 
    
         
            +
                    Janus.warn("Invalid handle");
         
     | 
| 
      
 1748 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 1749 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1750 
     | 
    
         
            +
                  let config = pluginHandle.webrtcStuff;
         
     | 
| 
      
 1751 
     | 
    
         
            +
                  if (!config.pc) {
         
     | 
| 
      
 1752 
     | 
    
         
            +
                    Janus.warn("Invalid PeerConnection");
         
     | 
| 
      
 1753 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 1754 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1755 
     | 
    
         
            +
                  let onDataChannelMessage = function (event) {
         
     | 
| 
      
 1756 
     | 
    
         
            +
                    Janus.log('Received message on data channel:', event);
         
     | 
| 
      
 1757 
     | 
    
         
            +
                    let label = event.target.label;
         
     | 
| 
      
 1758 
     | 
    
         
            +
                    pluginHandle.ondata(event.data, label);
         
     | 
| 
      
 1759 
     | 
    
         
            +
                  };
         
     | 
| 
      
 1760 
     | 
    
         
            +
                  let onDataChannelStateChange = function (event) {
         
     | 
| 
      
 1761 
     | 
    
         
            +
                    Janus.log('Received state change on data channel:', event);
         
     | 
| 
      
 1762 
     | 
    
         
            +
                    let label = event.target.label;
         
     | 
| 
      
 1763 
     | 
    
         
            +
                    let protocol = event.target.protocol;
         
     | 
| 
      
 1764 
     | 
    
         
            +
                    let dcState = config.dataChannel[label] ? config.dataChannel[label].readyState : "null";
         
     | 
| 
      
 1765 
     | 
    
         
            +
                    Janus.log('State change on <' + label + '> data channel: ' + dcState);
         
     | 
| 
      
 1766 
     | 
    
         
            +
                    if (dcState === 'open') {
         
     | 
| 
      
 1767 
     | 
    
         
            +
                      // Any pending messages to send?
         
     | 
| 
      
 1768 
     | 
    
         
            +
                      if (config.dataChannel[label].pending && config.dataChannel[label].pending.length > 0) {
         
     | 
| 
      
 1769 
     | 
    
         
            +
                        Janus.log("Sending pending messages on <" + label + ">:", config.dataChannel[label].pending.length);
         
     | 
| 
      
 1770 
     | 
    
         
            +
                        for (let data of config.dataChannel[label].pending) {
         
     | 
| 
      
 1771 
     | 
    
         
            +
                          Janus.log("Sending data on data channel <" + label + ">");
         
     | 
| 
      
 1772 
     | 
    
         
            +
                          Janus.debug(data);
         
     | 
| 
      
 1773 
     | 
    
         
            +
                          config.dataChannel[label].send(data);
         
     | 
| 
      
 1774 
     | 
    
         
            +
                        }
         
     | 
| 
      
 1775 
     | 
    
         
            +
                        config.dataChannel[label].pending = [];
         
     | 
| 
      
 1776 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1777 
     | 
    
         
            +
                      // Notify the open data channel
         
     | 
| 
      
 1778 
     | 
    
         
            +
                      pluginHandle.ondataopen(label, protocol);
         
     | 
| 
      
 1779 
     | 
    
         
            +
                    }
         
     | 
| 
      
 1780 
     | 
    
         
            +
                  };
         
     | 
| 
      
 1781 
     | 
    
         
            +
                  let onDataChannelError = function (error) {
         
     | 
| 
      
 1782 
     | 
    
         
            +
                    Janus.error('Got error on data channel:', error);
         
     | 
| 
      
 1783 
     | 
    
         
            +
                    // TODO
         
     | 
| 
      
 1784 
     | 
    
         
            +
                  };
         
     | 
| 
      
 1785 
     | 
    
         
            +
                  if (!incoming) {
         
     | 
| 
      
 1786 
     | 
    
         
            +
                    // FIXME Add options (ordered, maxRetransmits, etc.)
         
     | 
| 
      
 1787 
     | 
    
         
            +
                    let dcoptions = config.dataChannelOptions;
         
     | 
| 
      
 1788 
     | 
    
         
            +
                    if (dcprotocol) dcoptions.protocol = dcprotocol;
         
     | 
| 
      
 1789 
     | 
    
         
            +
                    config.dataChannel[dclabel] = config.pc.createDataChannel(dclabel, dcoptions);
         
     | 
| 
      
 1790 
     | 
    
         
            +
                  } else {
         
     | 
| 
      
 1791 
     | 
    
         
            +
                    // The channel was created by Janus
         
     | 
| 
      
 1792 
     | 
    
         
            +
                    config.dataChannel[dclabel] = incoming;
         
     | 
| 
      
 1793 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1794 
     | 
    
         
            +
                  config.dataChannel[dclabel].onmessage = onDataChannelMessage;
         
     | 
| 
      
 1795 
     | 
    
         
            +
                  config.dataChannel[dclabel].onopen = onDataChannelStateChange;
         
     | 
| 
      
 1796 
     | 
    
         
            +
                  config.dataChannel[dclabel].onclose = onDataChannelStateChange;
         
     | 
| 
      
 1797 
     | 
    
         
            +
                  config.dataChannel[dclabel].onerror = onDataChannelError;
         
     | 
| 
      
 1798 
     | 
    
         
            +
                  config.dataChannel[dclabel].pending = [];
         
     | 
| 
      
 1799 
     | 
    
         
            +
                  if (pendingData) config.dataChannel[dclabel].pending.push(pendingData);
         
     | 
| 
      
 1800 
     | 
    
         
            +
                }
         
     | 
| 
      
 1801 
     | 
    
         
            +
             
     | 
| 
      
 1802 
     | 
    
         
            +
                // Private method to send a data channel message
         
     | 
| 
      
 1803 
     | 
    
         
            +
                function sendData(handleId, callbacks) {
         
     | 
| 
      
 1804 
     | 
    
         
            +
                  callbacks = callbacks || {};
         
     | 
| 
      
 1805 
     | 
    
         
            +
                  callbacks.success = typeof callbacks.success == "function" ? callbacks.success : Janus.noop;
         
     | 
| 
      
 1806 
     | 
    
         
            +
                  callbacks.error = typeof callbacks.error == "function" ? callbacks.error : Janus.noop;
         
     | 
| 
      
 1807 
     | 
    
         
            +
                  let pluginHandle = pluginHandles.get(handleId);
         
     | 
| 
      
 1808 
     | 
    
         
            +
                  if (!pluginHandle || !pluginHandle.webrtcStuff) {
         
     | 
| 
      
 1809 
     | 
    
         
            +
                    Janus.warn("Invalid handle");
         
     | 
| 
      
 1810 
     | 
    
         
            +
                    callbacks.error("Invalid handle");
         
     | 
| 
      
 1811 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 1812 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1813 
     | 
    
         
            +
                  let config = pluginHandle.webrtcStuff;
         
     | 
| 
      
 1814 
     | 
    
         
            +
                  let data = callbacks.text || callbacks.data;
         
     | 
| 
      
 1815 
     | 
    
         
            +
                  if (!data) {
         
     | 
| 
      
 1816 
     | 
    
         
            +
                    Janus.warn("Invalid data");
         
     | 
| 
      
 1817 
     | 
    
         
            +
                    callbacks.error("Invalid data");
         
     | 
| 
      
 1818 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 1819 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1820 
     | 
    
         
            +
                  let label = callbacks.label ? callbacks.label : Janus.dataChanDefaultLabel;
         
     | 
| 
      
 1821 
     | 
    
         
            +
                  if (!config.dataChannel[label]) {
         
     | 
| 
      
 1822 
     | 
    
         
            +
                    // Create new data channel and wait for it to open
         
     | 
| 
      
 1823 
     | 
    
         
            +
                    createDataChannel(handleId, label, callbacks.protocol, false, data, callbacks.protocol);
         
     | 
| 
      
 1824 
     | 
    
         
            +
                    callbacks.success();
         
     | 
| 
      
 1825 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 1826 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1827 
     | 
    
         
            +
                  if (config.dataChannel[label].readyState !== "open") {
         
     | 
| 
      
 1828 
     | 
    
         
            +
                    config.dataChannel[label].pending.push(data);
         
     | 
| 
      
 1829 
     | 
    
         
            +
                    callbacks.success();
         
     | 
| 
      
 1830 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 1831 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1832 
     | 
    
         
            +
                  Janus.log("Sending data on data channel <" + label + ">");
         
     | 
| 
      
 1833 
     | 
    
         
            +
                  Janus.debug(data);
         
     | 
| 
      
 1834 
     | 
    
         
            +
                  config.dataChannel[label].send(data);
         
     | 
| 
      
 1835 
     | 
    
         
            +
                  callbacks.success();
         
     | 
| 
      
 1836 
     | 
    
         
            +
                }
         
     | 
| 
      
 1837 
     | 
    
         
            +
             
     | 
| 
      
 1838 
     | 
    
         
            +
                // Private method to send a DTMF tone
         
     | 
| 
      
 1839 
     | 
    
         
            +
                function sendDtmf(handleId, callbacks) {
         
     | 
| 
      
 1840 
     | 
    
         
            +
                  callbacks = callbacks || {};
         
     | 
| 
      
 1841 
     | 
    
         
            +
                  callbacks.success = typeof callbacks.success == "function" ? callbacks.success : Janus.noop;
         
     | 
| 
      
 1842 
     | 
    
         
            +
                  callbacks.error = typeof callbacks.error == "function" ? callbacks.error : Janus.noop;
         
     | 
| 
      
 1843 
     | 
    
         
            +
                  let pluginHandle = pluginHandles.get(handleId);
         
     | 
| 
      
 1844 
     | 
    
         
            +
                  if (!pluginHandle || !pluginHandle.webrtcStuff) {
         
     | 
| 
      
 1845 
     | 
    
         
            +
                    Janus.warn("Invalid handle");
         
     | 
| 
      
 1846 
     | 
    
         
            +
                    callbacks.error("Invalid handle");
         
     | 
| 
      
 1847 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 1848 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1849 
     | 
    
         
            +
                  let config = pluginHandle.webrtcStuff;
         
     | 
| 
      
 1850 
     | 
    
         
            +
                  if (!config.dtmfSender) {
         
     | 
| 
      
 1851 
     | 
    
         
            +
                    // Create the DTMF sender the proper way, if possible
         
     | 
| 
      
 1852 
     | 
    
         
            +
                    if (config.pc) {
         
     | 
| 
      
 1853 
     | 
    
         
            +
                      let senders = config.pc.getSenders();
         
     | 
| 
      
 1854 
     | 
    
         
            +
                      let audioSender = senders.find(function (sender) {
         
     | 
| 
      
 1855 
     | 
    
         
            +
                        return sender.track && sender.track.kind === 'audio';
         
     | 
| 
      
 1856 
     | 
    
         
            +
                      });
         
     | 
| 
      
 1857 
     | 
    
         
            +
                      if (!audioSender) {
         
     | 
| 
      
 1858 
     | 
    
         
            +
                        Janus.warn("Invalid DTMF configuration (no audio track)");
         
     | 
| 
      
 1859 
     | 
    
         
            +
                        callbacks.error("Invalid DTMF configuration (no audio track)");
         
     | 
| 
      
 1860 
     | 
    
         
            +
                        return;
         
     | 
| 
      
 1861 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1862 
     | 
    
         
            +
                      config.dtmfSender = audioSender.dtmf;
         
     | 
| 
      
 1863 
     | 
    
         
            +
                      if (config.dtmfSender) {
         
     | 
| 
      
 1864 
     | 
    
         
            +
                        Janus.log("Created DTMF Sender");
         
     | 
| 
      
 1865 
     | 
    
         
            +
                        config.dtmfSender.ontonechange = function (tone) {
         
     | 
| 
      
 1866 
     | 
    
         
            +
                          Janus.debug("Sent DTMF tone: " + tone.tone);
         
     | 
| 
      
 1867 
     | 
    
         
            +
                        };
         
     | 
| 
      
 1868 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1869 
     | 
    
         
            +
                    }
         
     | 
| 
      
 1870 
     | 
    
         
            +
                    if (!config.dtmfSender) {
         
     | 
| 
      
 1871 
     | 
    
         
            +
                      Janus.warn("Invalid DTMF configuration");
         
     | 
| 
      
 1872 
     | 
    
         
            +
                      callbacks.error("Invalid DTMF configuration");
         
     | 
| 
      
 1873 
     | 
    
         
            +
                      return;
         
     | 
| 
      
 1874 
     | 
    
         
            +
                    }
         
     | 
| 
      
 1875 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1876 
     | 
    
         
            +
                  let dtmf = callbacks.dtmf;
         
     | 
| 
      
 1877 
     | 
    
         
            +
                  if (!dtmf) {
         
     | 
| 
      
 1878 
     | 
    
         
            +
                    Janus.warn("Invalid DTMF parameters");
         
     | 
| 
      
 1879 
     | 
    
         
            +
                    callbacks.error("Invalid DTMF parameters");
         
     | 
| 
      
 1880 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 1881 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1882 
     | 
    
         
            +
                  let tones = dtmf.tones;
         
     | 
| 
      
 1883 
     | 
    
         
            +
                  if (!tones) {
         
     | 
| 
      
 1884 
     | 
    
         
            +
                    Janus.warn("Invalid DTMF string");
         
     | 
| 
      
 1885 
     | 
    
         
            +
                    callbacks.error("Invalid DTMF string");
         
     | 
| 
      
 1886 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 1887 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1888 
     | 
    
         
            +
                  let duration = typeof dtmf.duration === 'number' ? dtmf.duration : 500; // We choose 500ms as the default duration for a tone
         
     | 
| 
      
 1889 
     | 
    
         
            +
                  let gap = typeof dtmf.gap === 'number' ? dtmf.gap : 50; // We choose 50ms as the default gap between tones
         
     | 
| 
      
 1890 
     | 
    
         
            +
                  Janus.debug("Sending DTMF string " + tones + " (duration " + duration + "ms, gap " + gap + "ms)");
         
     | 
| 
      
 1891 
     | 
    
         
            +
                  config.dtmfSender.insertDTMF(tones, duration, gap);
         
     | 
| 
      
 1892 
     | 
    
         
            +
                  callbacks.success();
         
     | 
| 
      
 1893 
     | 
    
         
            +
                }
         
     | 
| 
      
 1894 
     | 
    
         
            +
             
     | 
| 
      
 1895 
     | 
    
         
            +
                // Private method to destroy a plugin handle
         
     | 
| 
      
 1896 
     | 
    
         
            +
                function destroyHandle(handleId, callbacks) {
         
     | 
| 
      
 1897 
     | 
    
         
            +
                  callbacks = callbacks || {};
         
     | 
| 
      
 1898 
     | 
    
         
            +
                  callbacks.success = typeof callbacks.success == "function" ? callbacks.success : Janus.noop;
         
     | 
| 
      
 1899 
     | 
    
         
            +
                  callbacks.error = typeof callbacks.error == "function" ? callbacks.error : Janus.noop;
         
     | 
| 
      
 1900 
     | 
    
         
            +
                  let noRequest = callbacks.noRequest === true;
         
     | 
| 
      
 1901 
     | 
    
         
            +
                  Janus.log("Destroying handle " + handleId + " (only-locally=" + noRequest + ")");
         
     | 
| 
      
 1902 
     | 
    
         
            +
                  cleanupWebrtc(handleId);
         
     | 
| 
      
 1903 
     | 
    
         
            +
                  let pluginHandle = pluginHandles.get(handleId);
         
     | 
| 
      
 1904 
     | 
    
         
            +
                  if (!pluginHandle || pluginHandle.detached) {
         
     | 
| 
      
 1905 
     | 
    
         
            +
                    // Plugin was already detached by Janus, calling detach again will return a handle not found error, so just exit here
         
     | 
| 
      
 1906 
     | 
    
         
            +
                    pluginHandles.delete(handleId);
         
     | 
| 
      
 1907 
     | 
    
         
            +
                    callbacks.success();
         
     | 
| 
      
 1908 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 1909 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1910 
     | 
    
         
            +
                  pluginHandle.detached = true;
         
     | 
| 
      
 1911 
     | 
    
         
            +
                  if (noRequest) {
         
     | 
| 
      
 1912 
     | 
    
         
            +
                    // We're only removing the handle locally
         
     | 
| 
      
 1913 
     | 
    
         
            +
                    pluginHandles.delete(handleId);
         
     | 
| 
      
 1914 
     | 
    
         
            +
                    callbacks.success();
         
     | 
| 
      
 1915 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 1916 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1917 
     | 
    
         
            +
                  if (!connected) {
         
     | 
| 
      
 1918 
     | 
    
         
            +
                    Janus.warn("Is the server down? (connected=false)");
         
     | 
| 
      
 1919 
     | 
    
         
            +
                    callbacks.error("Is the server down? (connected=false)");
         
     | 
| 
      
 1920 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 1921 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1922 
     | 
    
         
            +
                  let request = {
         
     | 
| 
      
 1923 
     | 
    
         
            +
                    "janus": "detach",
         
     | 
| 
      
 1924 
     | 
    
         
            +
                    "transaction": Janus.randomString(12)
         
     | 
| 
      
 1925 
     | 
    
         
            +
                  };
         
     | 
| 
      
 1926 
     | 
    
         
            +
                  if (pluginHandle.token) request["token"] = pluginHandle.token;
         
     | 
| 
      
 1927 
     | 
    
         
            +
                  if (apisecret) request["apisecret"] = apisecret;
         
     | 
| 
      
 1928 
     | 
    
         
            +
                  if (websockets) {
         
     | 
| 
      
 1929 
     | 
    
         
            +
                    request["session_id"] = sessionId;
         
     | 
| 
      
 1930 
     | 
    
         
            +
                    request["handle_id"] = handleId;
         
     | 
| 
      
 1931 
     | 
    
         
            +
                    ws.send(JSON.stringify(request));
         
     | 
| 
      
 1932 
     | 
    
         
            +
                    pluginHandles.delete(handleId);
         
     | 
| 
      
 1933 
     | 
    
         
            +
                    callbacks.success();
         
     | 
| 
      
 1934 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 1935 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1936 
     | 
    
         
            +
                  Janus.httpAPICall(server + "/" + sessionId + "/" + handleId, {
         
     | 
| 
      
 1937 
     | 
    
         
            +
                    verb: 'POST',
         
     | 
| 
      
 1938 
     | 
    
         
            +
                    withCredentials: withCredentials,
         
     | 
| 
      
 1939 
     | 
    
         
            +
                    body: request,
         
     | 
| 
      
 1940 
     | 
    
         
            +
                    success: function (json) {
         
     | 
| 
      
 1941 
     | 
    
         
            +
                      Janus.log("Destroyed handle:");
         
     | 
| 
      
 1942 
     | 
    
         
            +
                      Janus.debug(json);
         
     | 
| 
      
 1943 
     | 
    
         
            +
                      if (json["janus"] !== "success") {
         
     | 
| 
      
 1944 
     | 
    
         
            +
                        Janus.error("Ooops: " + json["error"].code + " " + json["error"].reason); // FIXME
         
     | 
| 
      
 1945 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1946 
     | 
    
         
            +
                      pluginHandles.delete(handleId);
         
     | 
| 
      
 1947 
     | 
    
         
            +
                      callbacks.success();
         
     | 
| 
      
 1948 
     | 
    
         
            +
                    },
         
     | 
| 
      
 1949 
     | 
    
         
            +
                    error: function (textStatus, errorThrown) {
         
     | 
| 
      
 1950 
     | 
    
         
            +
                      Janus.error(textStatus + ":", errorThrown); // FIXME
         
     | 
| 
      
 1951 
     | 
    
         
            +
                      // We cleanup anyway
         
     | 
| 
      
 1952 
     | 
    
         
            +
                      pluginHandles.delete(handleId);
         
     | 
| 
      
 1953 
     | 
    
         
            +
                      callbacks.success();
         
     | 
| 
      
 1954 
     | 
    
         
            +
                    }
         
     | 
| 
      
 1955 
     | 
    
         
            +
                  });
         
     | 
| 
      
 1956 
     | 
    
         
            +
                }
         
     | 
| 
      
 1957 
     | 
    
         
            +
             
     | 
| 
      
 1958 
     | 
    
         
            +
                // WebRTC stuff
         
     | 
| 
      
 1959 
     | 
    
         
            +
                // Helper function to create a new PeerConnection, if we need one
         
     | 
| 
      
 1960 
     | 
    
         
            +
                function createPeerconnectionIfNeeded(handleId, callbacks) {
         
     | 
| 
      
 1961 
     | 
    
         
            +
                  let pluginHandle = pluginHandles.get(handleId);
         
     | 
| 
      
 1962 
     | 
    
         
            +
                  if (!pluginHandle || !pluginHandle.webrtcStuff) {
         
     | 
| 
      
 1963 
     | 
    
         
            +
                    Janus.warn("Invalid handle");
         
     | 
| 
      
 1964 
     | 
    
         
            +
                    throw "Invalid handle";
         
     | 
| 
      
 1965 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1966 
     | 
    
         
            +
                  let config = pluginHandle.webrtcStuff;
         
     | 
| 
      
 1967 
     | 
    
         
            +
                  if (config.pc) {
         
     | 
| 
      
 1968 
     | 
    
         
            +
                    // Nothing to do, we have a PeerConnection already
         
     | 
| 
      
 1969 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 1970 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1971 
     | 
    
         
            +
                  let pc_config = {
         
     | 
| 
      
 1972 
     | 
    
         
            +
                    iceServers: iceServers,
         
     | 
| 
      
 1973 
     | 
    
         
            +
                    iceTransportPolicy: iceTransportPolicy,
         
     | 
| 
      
 1974 
     | 
    
         
            +
                    bundlePolicy: bundlePolicy
         
     | 
| 
      
 1975 
     | 
    
         
            +
                  };
         
     | 
| 
      
 1976 
     | 
    
         
            +
                  pc_config.sdpSemantics = 'unified-plan';
         
     | 
| 
      
 1977 
     | 
    
         
            +
                  // Check if a sender or receiver transform has been provided
         
     | 
| 
      
 1978 
     | 
    
         
            +
                  let insertableStreams = false;
         
     | 
| 
      
 1979 
     | 
    
         
            +
                  if (callbacks.tracks) {
         
     | 
| 
      
 1980 
     | 
    
         
            +
                    for (let track of callbacks.tracks) {
         
     | 
| 
      
 1981 
     | 
    
         
            +
                      if (track.transforms && (track.transforms.sender || track.transforms.receiver)) {
         
     | 
| 
      
 1982 
     | 
    
         
            +
                        insertableStreams = true;
         
     | 
| 
      
 1983 
     | 
    
         
            +
                        break;
         
     | 
| 
      
 1984 
     | 
    
         
            +
                      }
         
     | 
| 
      
 1985 
     | 
    
         
            +
                    }
         
     | 
| 
      
 1986 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1987 
     | 
    
         
            +
                  if (callbacks.externalEncryption) {
         
     | 
| 
      
 1988 
     | 
    
         
            +
                    insertableStreams = true;
         
     | 
| 
      
 1989 
     | 
    
         
            +
                    config.externalEncryption = true;
         
     | 
| 
      
 1990 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1991 
     | 
    
         
            +
                  if (RTCRtpSender && (RTCRtpSender.prototype.createEncodedStreams || RTCRtpSender.prototype.createEncodedAudioStreams && RTCRtpSender.prototype.createEncodedVideoStreams) && insertableStreams) {
         
     | 
| 
      
 1992 
     | 
    
         
            +
                    config.insertableStreams = true;
         
     | 
| 
      
 1993 
     | 
    
         
            +
                    pc_config.forceEncodedAudioInsertableStreams = true;
         
     | 
| 
      
 1994 
     | 
    
         
            +
                    pc_config.forceEncodedVideoInsertableStreams = true;
         
     | 
| 
      
 1995 
     | 
    
         
            +
                    pc_config.encodedInsertableStreams = true;
         
     | 
| 
      
 1996 
     | 
    
         
            +
                  }
         
     | 
| 
      
 1997 
     | 
    
         
            +
                  Janus.log('Creating PeerConnection');
         
     | 
| 
      
 1998 
     | 
    
         
            +
                  config.pc = new RTCPeerConnection(pc_config);
         
     | 
| 
      
 1999 
     | 
    
         
            +
                  Janus.debug(config.pc);
         
     | 
| 
      
 2000 
     | 
    
         
            +
                  if (config.pc.getStats) {
         
     | 
| 
      
 2001 
     | 
    
         
            +
                    // FIXME
         
     | 
| 
      
 2002 
     | 
    
         
            +
                    config.volume = {};
         
     | 
| 
      
 2003 
     | 
    
         
            +
                    config.bitrate.value = '0 kbits/sec';
         
     | 
| 
      
 2004 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2005 
     | 
    
         
            +
                  Janus.log('Preparing local SDP and gathering candidates (trickle=' + config.trickle + ')');
         
     | 
| 
      
 2006 
     | 
    
         
            +
                  config.pc.onconnectionstatechange = function () {
         
     | 
| 
      
 2007 
     | 
    
         
            +
                    if (config.pc) pluginHandle.connectionState(config.pc.connectionState);
         
     | 
| 
      
 2008 
     | 
    
         
            +
                  };
         
     | 
| 
      
 2009 
     | 
    
         
            +
                  config.pc.oniceconnectionstatechange = function () {
         
     | 
| 
      
 2010 
     | 
    
         
            +
                    if (config.pc) pluginHandle.iceState(config.pc.iceConnectionState);
         
     | 
| 
      
 2011 
     | 
    
         
            +
                  };
         
     | 
| 
      
 2012 
     | 
    
         
            +
                  config.pc.onicecandidate = function (event) {
         
     | 
| 
      
 2013 
     | 
    
         
            +
                    if (!event.candidate || event.candidate.candidate && event.candidate.candidate.indexOf('endOfCandidates') > 0) {
         
     | 
| 
      
 2014 
     | 
    
         
            +
                      Janus.log('End of candidates.');
         
     | 
| 
      
 2015 
     | 
    
         
            +
                      config.iceDone = true;
         
     | 
| 
      
 2016 
     | 
    
         
            +
                      if (config.trickle === true) {
         
     | 
| 
      
 2017 
     | 
    
         
            +
                        // Notify end of candidates
         
     | 
| 
      
 2018 
     | 
    
         
            +
                        sendTrickleCandidate(handleId, {
         
     | 
| 
      
 2019 
     | 
    
         
            +
                          completed: true
         
     | 
| 
      
 2020 
     | 
    
         
            +
                        });
         
     | 
| 
      
 2021 
     | 
    
         
            +
                      } else {
         
     | 
| 
      
 2022 
     | 
    
         
            +
                        // No trickle, time to send the complete SDP (including all candidates)
         
     | 
| 
      
 2023 
     | 
    
         
            +
                        sendSDP(handleId, callbacks);
         
     | 
| 
      
 2024 
     | 
    
         
            +
                      }
         
     | 
| 
      
 2025 
     | 
    
         
            +
                    } else {
         
     | 
| 
      
 2026 
     | 
    
         
            +
                      // JSON.stringify doesn't work on some WebRTC objects anymore
         
     | 
| 
      
 2027 
     | 
    
         
            +
                      // See https://code.google.com/p/chromium/issues/detail?id=467366
         
     | 
| 
      
 2028 
     | 
    
         
            +
                      let candidate = {
         
     | 
| 
      
 2029 
     | 
    
         
            +
                        candidate: event.candidate.candidate,
         
     | 
| 
      
 2030 
     | 
    
         
            +
                        sdpMid: event.candidate.sdpMid,
         
     | 
| 
      
 2031 
     | 
    
         
            +
                        sdpMLineIndex: event.candidate.sdpMLineIndex
         
     | 
| 
      
 2032 
     | 
    
         
            +
                      };
         
     | 
| 
      
 2033 
     | 
    
         
            +
                      if (config.trickle === true) {
         
     | 
| 
      
 2034 
     | 
    
         
            +
                        // Send candidate
         
     | 
| 
      
 2035 
     | 
    
         
            +
                        sendTrickleCandidate(handleId, candidate);
         
     | 
| 
      
 2036 
     | 
    
         
            +
                      }
         
     | 
| 
      
 2037 
     | 
    
         
            +
                    }
         
     | 
| 
      
 2038 
     | 
    
         
            +
                  };
         
     | 
| 
      
 2039 
     | 
    
         
            +
                  config.pc.ontrack = function (event) {
         
     | 
| 
      
 2040 
     | 
    
         
            +
                    Janus.log('Handling Remote Track', event);
         
     | 
| 
      
 2041 
     | 
    
         
            +
                    if (!event.streams) return;
         
     | 
| 
      
 2042 
     | 
    
         
            +
                    if (!event.track) return;
         
     | 
| 
      
 2043 
     | 
    
         
            +
                    // Notify about the new track event
         
     | 
| 
      
 2044 
     | 
    
         
            +
                    let mid = event.transceiver ? event.transceiver.mid : event.track.id;
         
     | 
| 
      
 2045 
     | 
    
         
            +
                    try {
         
     | 
| 
      
 2046 
     | 
    
         
            +
                      if (event.transceiver && event.transceiver.mid && event.track.id) {
         
     | 
| 
      
 2047 
     | 
    
         
            +
                        // Keep track of the mapping between track ID and mid, since
         
     | 
| 
      
 2048 
     | 
    
         
            +
                        // when a track is removed the transceiver may be gone already
         
     | 
| 
      
 2049 
     | 
    
         
            +
                        if (!pluginHandle.mids) pluginHandle.mids = {};
         
     | 
| 
      
 2050 
     | 
    
         
            +
                        pluginHandle.mids[event.track.id] = event.transceiver.mid;
         
     | 
| 
      
 2051 
     | 
    
         
            +
                      }
         
     | 
| 
      
 2052 
     | 
    
         
            +
                      pluginHandle.onremotetrack(event.track, mid, true, {
         
     | 
| 
      
 2053 
     | 
    
         
            +
                        reason: 'created'
         
     | 
| 
      
 2054 
     | 
    
         
            +
                      });
         
     | 
| 
      
 2055 
     | 
    
         
            +
                    } catch (e) {
         
     | 
| 
      
 2056 
     | 
    
         
            +
                      Janus.error("Error calling onremotetrack", e);
         
     | 
| 
      
 2057 
     | 
    
         
            +
                    }
         
     | 
| 
      
 2058 
     | 
    
         
            +
                    if (event.track.onended) return;
         
     | 
| 
      
 2059 
     | 
    
         
            +
                    let trackMutedTimeoutId = null;
         
     | 
| 
      
 2060 
     | 
    
         
            +
                    Janus.log('Adding onended callback to track:', event.track);
         
     | 
| 
      
 2061 
     | 
    
         
            +
                    event.track.onended = function (ev) {
         
     | 
| 
      
 2062 
     | 
    
         
            +
                      Janus.log('Remote track removed:', ev);
         
     | 
| 
      
 2063 
     | 
    
         
            +
                      clearTimeout(trackMutedTimeoutId);
         
     | 
| 
      
 2064 
     | 
    
         
            +
                      // Notify the application
         
     | 
| 
      
 2065 
     | 
    
         
            +
                      let transceivers = config.pc ? config.pc.getTransceivers() : null;
         
     | 
| 
      
 2066 
     | 
    
         
            +
                      let transceiver = transceivers ? transceivers.find(t => t.receiver.track === ev.target) : null;
         
     | 
| 
      
 2067 
     | 
    
         
            +
                      let mid = transceiver ? transceiver.mid : ev.target.id;
         
     | 
| 
      
 2068 
     | 
    
         
            +
                      if (mid === ev.target.id && pluginHandle.mids && pluginHandle.mids[event.track.id]) mid = pluginHandle.mids[event.track.id];
         
     | 
| 
      
 2069 
     | 
    
         
            +
                      try {
         
     | 
| 
      
 2070 
     | 
    
         
            +
                        pluginHandle.onremotetrack(ev.target, mid, false, {
         
     | 
| 
      
 2071 
     | 
    
         
            +
                          reason: 'ended'
         
     | 
| 
      
 2072 
     | 
    
         
            +
                        });
         
     | 
| 
      
 2073 
     | 
    
         
            +
                      } catch (e) {
         
     | 
| 
      
 2074 
     | 
    
         
            +
                        Janus.error("Error calling onremotetrack on removal", e);
         
     | 
| 
      
 2075 
     | 
    
         
            +
                      }
         
     | 
| 
      
 2076 
     | 
    
         
            +
                      delete pluginHandle.mids[event.track.id];
         
     | 
| 
      
 2077 
     | 
    
         
            +
                    };
         
     | 
| 
      
 2078 
     | 
    
         
            +
                    event.track.onmute = function (ev) {
         
     | 
| 
      
 2079 
     | 
    
         
            +
                      Janus.log('Remote track muted:', ev);
         
     | 
| 
      
 2080 
     | 
    
         
            +
                      if (!trackMutedTimeoutId) {
         
     | 
| 
      
 2081 
     | 
    
         
            +
                        trackMutedTimeoutId = setTimeout(function () {
         
     | 
| 
      
 2082 
     | 
    
         
            +
                          Janus.log('Removing remote track');
         
     | 
| 
      
 2083 
     | 
    
         
            +
                          // Notify the application the track is gone
         
     | 
| 
      
 2084 
     | 
    
         
            +
                          let transceivers = config.pc ? config.pc.getTransceivers() : null;
         
     | 
| 
      
 2085 
     | 
    
         
            +
                          let transceiver = transceivers ? transceivers.find(t => t.receiver.track === ev.target) : null;
         
     | 
| 
      
 2086 
     | 
    
         
            +
                          let mid = transceiver ? transceiver.mid : ev.target.id;
         
     | 
| 
      
 2087 
     | 
    
         
            +
                          if (mid === ev.target.id && pluginHandle.mids && pluginHandle.mids[event.track.id]) mid = pluginHandle.mids[event.track.id];
         
     | 
| 
      
 2088 
     | 
    
         
            +
                          try {
         
     | 
| 
      
 2089 
     | 
    
         
            +
                            pluginHandle.onremotetrack(ev.target, mid, false, {
         
     | 
| 
      
 2090 
     | 
    
         
            +
                              reason: 'mute'
         
     | 
| 
      
 2091 
     | 
    
         
            +
                            });
         
     | 
| 
      
 2092 
     | 
    
         
            +
                          } catch (e) {
         
     | 
| 
      
 2093 
     | 
    
         
            +
                            Janus.error("Error calling onremotetrack on mute", e);
         
     | 
| 
      
 2094 
     | 
    
         
            +
                          }
         
     | 
| 
      
 2095 
     | 
    
         
            +
                          trackMutedTimeoutId = null;
         
     | 
| 
      
 2096 
     | 
    
         
            +
                          // Chrome seems to raise mute events only at multiples of 834ms;
         
     | 
| 
      
 2097 
     | 
    
         
            +
                          // we set the timeout to three times this value (rounded to 840ms)
         
     | 
| 
      
 2098 
     | 
    
         
            +
                        }, 3 * 840);
         
     | 
| 
      
 2099 
     | 
    
         
            +
                      }
         
     | 
| 
      
 2100 
     | 
    
         
            +
                    };
         
     | 
| 
      
 2101 
     | 
    
         
            +
                    event.track.onunmute = function (ev) {
         
     | 
| 
      
 2102 
     | 
    
         
            +
                      Janus.log('Remote track flowing again:', ev);
         
     | 
| 
      
 2103 
     | 
    
         
            +
                      if (trackMutedTimeoutId != null) {
         
     | 
| 
      
 2104 
     | 
    
         
            +
                        clearTimeout(trackMutedTimeoutId);
         
     | 
| 
      
 2105 
     | 
    
         
            +
                        trackMutedTimeoutId = null;
         
     | 
| 
      
 2106 
     | 
    
         
            +
                      } else {
         
     | 
| 
      
 2107 
     | 
    
         
            +
                        try {
         
     | 
| 
      
 2108 
     | 
    
         
            +
                          // Notify the application the track is back
         
     | 
| 
      
 2109 
     | 
    
         
            +
                          let transceivers = config.pc ? config.pc.getTransceivers() : null;
         
     | 
| 
      
 2110 
     | 
    
         
            +
                          let transceiver = transceivers ? transceivers.find(t => t.receiver.track === ev.target) : null;
         
     | 
| 
      
 2111 
     | 
    
         
            +
                          let mid = transceiver ? transceiver.mid : ev.target.id;
         
     | 
| 
      
 2112 
     | 
    
         
            +
                          pluginHandle.onremotetrack(ev.target, mid, true, {
         
     | 
| 
      
 2113 
     | 
    
         
            +
                            reason: 'unmute'
         
     | 
| 
      
 2114 
     | 
    
         
            +
                          });
         
     | 
| 
      
 2115 
     | 
    
         
            +
                        } catch (e) {
         
     | 
| 
      
 2116 
     | 
    
         
            +
                          Janus.error("Error calling onremotetrack on unmute", e);
         
     | 
| 
      
 2117 
     | 
    
         
            +
                        }
         
     | 
| 
      
 2118 
     | 
    
         
            +
                      }
         
     | 
| 
      
 2119 
     | 
    
         
            +
                    };
         
     | 
| 
      
 2120 
     | 
    
         
            +
                  };
         
     | 
| 
      
 2121 
     | 
    
         
            +
                }
         
     | 
| 
      
 2122 
     | 
    
         
            +
             
     | 
| 
      
 2123 
     | 
    
         
            +
                // Helper function used when creating either an offer or answer: it
         
     | 
| 
      
 2124 
     | 
    
         
            +
                // prepares what needs to be prepared, including creating a new
         
     | 
| 
      
 2125 
     | 
    
         
            +
                // PeerConnection (if needed) and updating the tracks configuration,
         
     | 
| 
      
 2126 
     | 
    
         
            +
                // before invoking the function to actually generate the offer/answer
         
     | 
| 
      
 2127 
     | 
    
         
            +
                async function prepareWebrtc(handleId, offer, callbacks) {
         
     | 
| 
      
 2128 
     | 
    
         
            +
                  callbacks = callbacks || {};
         
     | 
| 
      
 2129 
     | 
    
         
            +
                  callbacks.success = typeof callbacks.success == "function" ? callbacks.success : Janus.noop;
         
     | 
| 
      
 2130 
     | 
    
         
            +
                  callbacks.error = typeof callbacks.error == "function" ? callbacks.error : webrtcError;
         
     | 
| 
      
 2131 
     | 
    
         
            +
                  let jsep = callbacks.jsep;
         
     | 
| 
      
 2132 
     | 
    
         
            +
                  if (offer && jsep) {
         
     | 
| 
      
 2133 
     | 
    
         
            +
                    Janus.error("Provided a JSEP to a createOffer");
         
     | 
| 
      
 2134 
     | 
    
         
            +
                    callbacks.error("Provided a JSEP to a createOffer");
         
     | 
| 
      
 2135 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 2136 
     | 
    
         
            +
                  } else if (!offer && (!jsep || !jsep.type || !jsep.sdp)) {
         
     | 
| 
      
 2137 
     | 
    
         
            +
                    Janus.error("A valid JSEP is required for createAnswer");
         
     | 
| 
      
 2138 
     | 
    
         
            +
                    callbacks.error("A valid JSEP is required for createAnswer");
         
     | 
| 
      
 2139 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 2140 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2141 
     | 
    
         
            +
                  // If the deprecated media was provided instead of tracks, translate it
         
     | 
| 
      
 2142 
     | 
    
         
            +
                  if (callbacks.media && !callbacks.tracks) {
         
     | 
| 
      
 2143 
     | 
    
         
            +
                    callbacks.tracks = Janus.mediaToTracks(callbacks.media);
         
     | 
| 
      
 2144 
     | 
    
         
            +
                    if (callbacks.simulcast === true || callbacks.simulcast2 === true || callbacks.svc) {
         
     | 
| 
      
 2145 
     | 
    
         
            +
                      // Find the video track and add simulcast/SVC info there
         
     | 
| 
      
 2146 
     | 
    
         
            +
                      for (let track of callbacks.tracks) {
         
     | 
| 
      
 2147 
     | 
    
         
            +
                        if (track.type === 'video') {
         
     | 
| 
      
 2148 
     | 
    
         
            +
                          if (callbacks.simulcast === true || callbacks.simulcast2 === true) track.simulcast = true;else if (callbacks.svc) track.svc = callbacks.svc;
         
     | 
| 
      
 2149 
     | 
    
         
            +
                          break;
         
     | 
| 
      
 2150 
     | 
    
         
            +
                        }
         
     | 
| 
      
 2151 
     | 
    
         
            +
                      }
         
     | 
| 
      
 2152 
     | 
    
         
            +
                    }
         
     | 
| 
      
 2153 
     | 
    
         
            +
                    Janus.warn('Deprecated media object passed, use tracks instead. Automatically translated to:', callbacks.tracks);
         
     | 
| 
      
 2154 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2155 
     | 
    
         
            +
                  // Check that callbacks.array is a valid array
         
     | 
| 
      
 2156 
     | 
    
         
            +
                  if (callbacks.tracks && !Array.isArray(callbacks.tracks)) {
         
     | 
| 
      
 2157 
     | 
    
         
            +
                    Janus.error("Tracks must be an array");
         
     | 
| 
      
 2158 
     | 
    
         
            +
                    callbacks.error("Tracks must be an array");
         
     | 
| 
      
 2159 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 2160 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2161 
     | 
    
         
            +
                  // Get the plugin handle
         
     | 
| 
      
 2162 
     | 
    
         
            +
                  let pluginHandle = pluginHandles.get(handleId);
         
     | 
| 
      
 2163 
     | 
    
         
            +
                  if (!pluginHandle || !pluginHandle.webrtcStuff) {
         
     | 
| 
      
 2164 
     | 
    
         
            +
                    Janus.warn("Invalid handle");
         
     | 
| 
      
 2165 
     | 
    
         
            +
                    callbacks.error("Invalid handle");
         
     | 
| 
      
 2166 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 2167 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2168 
     | 
    
         
            +
                  let config = pluginHandle.webrtcStuff;
         
     | 
| 
      
 2169 
     | 
    
         
            +
                  config.trickle = isTrickleEnabled(callbacks.trickle);
         
     | 
| 
      
 2170 
     | 
    
         
            +
                  try {
         
     | 
| 
      
 2171 
     | 
    
         
            +
                    // Create a PeerConnection, if needed
         
     | 
| 
      
 2172 
     | 
    
         
            +
                    createPeerconnectionIfNeeded(handleId, callbacks);
         
     | 
| 
      
 2173 
     | 
    
         
            +
                    if (offer) {
         
     | 
| 
      
 2174 
     | 
    
         
            +
                      // Capture devices and setup tracks, if needed
         
     | 
| 
      
 2175 
     | 
    
         
            +
                      await captureDevices(handleId, callbacks);
         
     | 
| 
      
 2176 
     | 
    
         
            +
                    }
         
     | 
| 
      
 2177 
     | 
    
         
            +
                    // Create offer or answer now (depending on the context)
         
     | 
| 
      
 2178 
     | 
    
         
            +
                    if (!jsep) {
         
     | 
| 
      
 2179 
     | 
    
         
            +
                      let offer = await createOffer(handleId, callbacks);
         
     | 
| 
      
 2180 
     | 
    
         
            +
                      callbacks.success(offer);
         
     | 
| 
      
 2181 
     | 
    
         
            +
                    } else {
         
     | 
| 
      
 2182 
     | 
    
         
            +
                      await config.pc.setRemoteDescription(jsep);
         
     | 
| 
      
 2183 
     | 
    
         
            +
                      Janus.log("Remote description accepted!");
         
     | 
| 
      
 2184 
     | 
    
         
            +
                      config.remoteSdp = jsep.sdp;
         
     | 
| 
      
 2185 
     | 
    
         
            +
                      // Any trickle candidate we cached?
         
     | 
| 
      
 2186 
     | 
    
         
            +
                      if (config.candidates && config.candidates.length > 0) {
         
     | 
| 
      
 2187 
     | 
    
         
            +
                        for (let i = 0; i < config.candidates.length; i++) {
         
     | 
| 
      
 2188 
     | 
    
         
            +
                          let candidate = config.candidates[i];
         
     | 
| 
      
 2189 
     | 
    
         
            +
                          Janus.debug("Adding remote candidate:", candidate);
         
     | 
| 
      
 2190 
     | 
    
         
            +
                          if (!candidate || candidate.completed === true) {
         
     | 
| 
      
 2191 
     | 
    
         
            +
                            // end-of-candidates
         
     | 
| 
      
 2192 
     | 
    
         
            +
                            config.pc.addIceCandidate(Janus.endOfCandidates);
         
     | 
| 
      
 2193 
     | 
    
         
            +
                          } else {
         
     | 
| 
      
 2194 
     | 
    
         
            +
                            // New candidate
         
     | 
| 
      
 2195 
     | 
    
         
            +
                            config.pc.addIceCandidate(candidate);
         
     | 
| 
      
 2196 
     | 
    
         
            +
                          }
         
     | 
| 
      
 2197 
     | 
    
         
            +
                        }
         
     | 
| 
      
 2198 
     | 
    
         
            +
                        config.candidates = [];
         
     | 
| 
      
 2199 
     | 
    
         
            +
                      }
         
     | 
| 
      
 2200 
     | 
    
         
            +
                      // Capture devices and setup tracks, if needed
         
     | 
| 
      
 2201 
     | 
    
         
            +
                      await captureDevices(handleId, callbacks);
         
     | 
| 
      
 2202 
     | 
    
         
            +
                      // Create the answer now
         
     | 
| 
      
 2203 
     | 
    
         
            +
                      let answer = await createAnswer(handleId, callbacks);
         
     | 
| 
      
 2204 
     | 
    
         
            +
                      callbacks.success(answer);
         
     | 
| 
      
 2205 
     | 
    
         
            +
                    }
         
     | 
| 
      
 2206 
     | 
    
         
            +
                  } catch (err) {
         
     | 
| 
      
 2207 
     | 
    
         
            +
                    Janus.error(err);
         
     | 
| 
      
 2208 
     | 
    
         
            +
                    callbacks.error(err);
         
     | 
| 
      
 2209 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2210 
     | 
    
         
            +
                }
         
     | 
| 
      
 2211 
     | 
    
         
            +
                function prepareWebrtcPeer(handleId, callbacks) {
         
     | 
| 
      
 2212 
     | 
    
         
            +
                  callbacks = callbacks || {};
         
     | 
| 
      
 2213 
     | 
    
         
            +
                  callbacks.success = typeof callbacks.success == "function" ? callbacks.success : Janus.noop;
         
     | 
| 
      
 2214 
     | 
    
         
            +
                  callbacks.error = typeof callbacks.error == "function" ? callbacks.error : webrtcError;
         
     | 
| 
      
 2215 
     | 
    
         
            +
                  callbacks.customizeSdp = typeof callbacks.customizeSdp == "function" ? callbacks.customizeSdp : Janus.noop;
         
     | 
| 
      
 2216 
     | 
    
         
            +
                  let jsep = callbacks.jsep;
         
     | 
| 
      
 2217 
     | 
    
         
            +
                  let pluginHandle = pluginHandles.get(handleId);
         
     | 
| 
      
 2218 
     | 
    
         
            +
                  if (!pluginHandle || !pluginHandle.webrtcStuff) {
         
     | 
| 
      
 2219 
     | 
    
         
            +
                    Janus.warn("Invalid handle");
         
     | 
| 
      
 2220 
     | 
    
         
            +
                    callbacks.error("Invalid handle");
         
     | 
| 
      
 2221 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 2222 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2223 
     | 
    
         
            +
                  let config = pluginHandle.webrtcStuff;
         
     | 
| 
      
 2224 
     | 
    
         
            +
                  if (jsep) {
         
     | 
| 
      
 2225 
     | 
    
         
            +
                    if (!config.pc) {
         
     | 
| 
      
 2226 
     | 
    
         
            +
                      Janus.warn("Wait, no PeerConnection?? if this is an answer, use createAnswer and not handleRemoteJsep");
         
     | 
| 
      
 2227 
     | 
    
         
            +
                      callbacks.error("No PeerConnection: if this is an answer, use createAnswer and not handleRemoteJsep");
         
     | 
| 
      
 2228 
     | 
    
         
            +
                      return;
         
     | 
| 
      
 2229 
     | 
    
         
            +
                    }
         
     | 
| 
      
 2230 
     | 
    
         
            +
                    callbacks.customizeSdp(jsep);
         
     | 
| 
      
 2231 
     | 
    
         
            +
                    config.pc.setRemoteDescription(jsep).then(function () {
         
     | 
| 
      
 2232 
     | 
    
         
            +
                      Janus.log("Remote description accepted!");
         
     | 
| 
      
 2233 
     | 
    
         
            +
                      config.remoteSdp = jsep.sdp;
         
     | 
| 
      
 2234 
     | 
    
         
            +
                      // Any trickle candidate we cached?
         
     | 
| 
      
 2235 
     | 
    
         
            +
                      if (config.candidates && config.candidates.length > 0) {
         
     | 
| 
      
 2236 
     | 
    
         
            +
                        for (let i = 0; i < config.candidates.length; i++) {
         
     | 
| 
      
 2237 
     | 
    
         
            +
                          let candidate = config.candidates[i];
         
     | 
| 
      
 2238 
     | 
    
         
            +
                          Janus.debug("Adding remote candidate:", candidate);
         
     | 
| 
      
 2239 
     | 
    
         
            +
                          if (!candidate || candidate.completed === true) {
         
     | 
| 
      
 2240 
     | 
    
         
            +
                            // end-of-candidates
         
     | 
| 
      
 2241 
     | 
    
         
            +
                            config.pc.addIceCandidate(Janus.endOfCandidates);
         
     | 
| 
      
 2242 
     | 
    
         
            +
                          } else {
         
     | 
| 
      
 2243 
     | 
    
         
            +
                            // New candidate
         
     | 
| 
      
 2244 
     | 
    
         
            +
                            config.pc.addIceCandidate(candidate);
         
     | 
| 
      
 2245 
     | 
    
         
            +
                          }
         
     | 
| 
      
 2246 
     | 
    
         
            +
                        }
         
     | 
| 
      
 2247 
     | 
    
         
            +
                        config.candidates = [];
         
     | 
| 
      
 2248 
     | 
    
         
            +
                      }
         
     | 
| 
      
 2249 
     | 
    
         
            +
                      // Done
         
     | 
| 
      
 2250 
     | 
    
         
            +
                      callbacks.success();
         
     | 
| 
      
 2251 
     | 
    
         
            +
                    }, callbacks.error);
         
     | 
| 
      
 2252 
     | 
    
         
            +
                  } else {
         
     | 
| 
      
 2253 
     | 
    
         
            +
                    callbacks.error("Invalid JSEP");
         
     | 
| 
      
 2254 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2255 
     | 
    
         
            +
                }
         
     | 
| 
      
 2256 
     | 
    
         
            +
                async function createOffer(handleId, callbacks) {
         
     | 
| 
      
 2257 
     | 
    
         
            +
                  callbacks = callbacks || {};
         
     | 
| 
      
 2258 
     | 
    
         
            +
                  callbacks.customizeSdp = typeof callbacks.customizeSdp == "function" ? callbacks.customizeSdp : Janus.noop;
         
     | 
| 
      
 2259 
     | 
    
         
            +
                  let pluginHandle = pluginHandles.get(handleId);
         
     | 
| 
      
 2260 
     | 
    
         
            +
                  if (!pluginHandle || !pluginHandle.webrtcStuff) {
         
     | 
| 
      
 2261 
     | 
    
         
            +
                    Janus.warn("Invalid handle");
         
     | 
| 
      
 2262 
     | 
    
         
            +
                    throw "Invalid handle";
         
     | 
| 
      
 2263 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2264 
     | 
    
         
            +
                  let config = pluginHandle.webrtcStuff;
         
     | 
| 
      
 2265 
     | 
    
         
            +
                  Janus.log("Creating offer (iceDone=" + config.iceDone + ")");
         
     | 
| 
      
 2266 
     | 
    
         
            +
                  // https://code.google.com/p/webrtc/issues/detail?id=3508
         
     | 
| 
      
 2267 
     | 
    
         
            +
                  let mediaConstraints = {};
         
     | 
| 
      
 2268 
     | 
    
         
            +
                  let iceRestart = callbacks.iceRestart === true;
         
     | 
| 
      
 2269 
     | 
    
         
            +
                  // If we need an ICE restart, set the related constraint
         
     | 
| 
      
 2270 
     | 
    
         
            +
                  if (iceRestart) mediaConstraints.iceRestart = true;
         
     | 
| 
      
 2271 
     | 
    
         
            +
                  Janus.debug(mediaConstraints);
         
     | 
| 
      
 2272 
     | 
    
         
            +
                  let offer = await config.pc.createOffer(mediaConstraints);
         
     | 
| 
      
 2273 
     | 
    
         
            +
                  Janus.debug(offer);
         
     | 
| 
      
 2274 
     | 
    
         
            +
                  // JSON.stringify doesn't work on some WebRTC objects anymore
         
     | 
| 
      
 2275 
     | 
    
         
            +
                  // See https://code.google.com/p/chromium/issues/detail?id=467366
         
     | 
| 
      
 2276 
     | 
    
         
            +
                  let jsep = {
         
     | 
| 
      
 2277 
     | 
    
         
            +
                    type: 'offer',
         
     | 
| 
      
 2278 
     | 
    
         
            +
                    sdp: offer.sdp
         
     | 
| 
      
 2279 
     | 
    
         
            +
                  };
         
     | 
| 
      
 2280 
     | 
    
         
            +
                  callbacks.customizeSdp(jsep);
         
     | 
| 
      
 2281 
     | 
    
         
            +
                  offer.sdp = jsep.sdp;
         
     | 
| 
      
 2282 
     | 
    
         
            +
                  Janus.log("Setting local description");
         
     | 
| 
      
 2283 
     | 
    
         
            +
                  config.mySdp = {
         
     | 
| 
      
 2284 
     | 
    
         
            +
                    type: 'offer',
         
     | 
| 
      
 2285 
     | 
    
         
            +
                    sdp: offer.sdp
         
     | 
| 
      
 2286 
     | 
    
         
            +
                  };
         
     | 
| 
      
 2287 
     | 
    
         
            +
                  await config.pc.setLocalDescription(offer);
         
     | 
| 
      
 2288 
     | 
    
         
            +
                  config.mediaConstraints = mediaConstraints;
         
     | 
| 
      
 2289 
     | 
    
         
            +
                  if (!config.iceDone && !config.trickle) {
         
     | 
| 
      
 2290 
     | 
    
         
            +
                    // FIXME Don't do anything until we have all candidates
         
     | 
| 
      
 2291 
     | 
    
         
            +
                    Janus.log("Waiting for all candidates...");
         
     | 
| 
      
 2292 
     | 
    
         
            +
                    return null;
         
     | 
| 
      
 2293 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2294 
     | 
    
         
            +
                  // If transforms are present, notify Janus that the media is end-to-end encrypted
         
     | 
| 
      
 2295 
     | 
    
         
            +
                  if (config.insertableStreams || config.externalEncryption) offer.e2ee = true;
         
     | 
| 
      
 2296 
     | 
    
         
            +
                  return offer;
         
     | 
| 
      
 2297 
     | 
    
         
            +
                }
         
     | 
| 
      
 2298 
     | 
    
         
            +
                async function createAnswer(handleId, callbacks) {
         
     | 
| 
      
 2299 
     | 
    
         
            +
                  callbacks = callbacks || {};
         
     | 
| 
      
 2300 
     | 
    
         
            +
                  callbacks.customizeSdp = typeof callbacks.customizeSdp == "function" ? callbacks.customizeSdp : Janus.noop;
         
     | 
| 
      
 2301 
     | 
    
         
            +
                  let pluginHandle = pluginHandles.get(handleId);
         
     | 
| 
      
 2302 
     | 
    
         
            +
                  if (!pluginHandle || !pluginHandle.webrtcStuff) {
         
     | 
| 
      
 2303 
     | 
    
         
            +
                    Janus.warn("Invalid handle");
         
     | 
| 
      
 2304 
     | 
    
         
            +
                    throw "Invalid handle";
         
     | 
| 
      
 2305 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2306 
     | 
    
         
            +
                  let config = pluginHandle.webrtcStuff;
         
     | 
| 
      
 2307 
     | 
    
         
            +
                  Janus.log("Creating answer (iceDone=" + config.iceDone + ")");
         
     | 
| 
      
 2308 
     | 
    
         
            +
                  let answer = await config.pc.createAnswer();
         
     | 
| 
      
 2309 
     | 
    
         
            +
                  Janus.debug(answer);
         
     | 
| 
      
 2310 
     | 
    
         
            +
                  // JSON.stringify doesn't work on some WebRTC objects anymore
         
     | 
| 
      
 2311 
     | 
    
         
            +
                  // See https://code.google.com/p/chromium/issues/detail?id=467366
         
     | 
| 
      
 2312 
     | 
    
         
            +
                  let jsep = {
         
     | 
| 
      
 2313 
     | 
    
         
            +
                    type: 'answer',
         
     | 
| 
      
 2314 
     | 
    
         
            +
                    sdp: answer.sdp
         
     | 
| 
      
 2315 
     | 
    
         
            +
                  };
         
     | 
| 
      
 2316 
     | 
    
         
            +
                  callbacks.customizeSdp(jsep);
         
     | 
| 
      
 2317 
     | 
    
         
            +
                  answer.sdp = jsep.sdp;
         
     | 
| 
      
 2318 
     | 
    
         
            +
                  Janus.log("Setting local description");
         
     | 
| 
      
 2319 
     | 
    
         
            +
                  config.mySdp = {
         
     | 
| 
      
 2320 
     | 
    
         
            +
                    type: 'answer',
         
     | 
| 
      
 2321 
     | 
    
         
            +
                    sdp: answer.sdp
         
     | 
| 
      
 2322 
     | 
    
         
            +
                  };
         
     | 
| 
      
 2323 
     | 
    
         
            +
                  await config.pc.setLocalDescription(answer);
         
     | 
| 
      
 2324 
     | 
    
         
            +
                  if (!config.iceDone && !config.trickle) {
         
     | 
| 
      
 2325 
     | 
    
         
            +
                    // FIXME Don't do anything until we have all candidates
         
     | 
| 
      
 2326 
     | 
    
         
            +
                    Janus.log("Waiting for all candidates...");
         
     | 
| 
      
 2327 
     | 
    
         
            +
                    return null;
         
     | 
| 
      
 2328 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2329 
     | 
    
         
            +
                  // If transforms are present, notify Janus that the media is end-to-end encrypted
         
     | 
| 
      
 2330 
     | 
    
         
            +
                  if (config.insertableStreams || config.externalEncryption) answer.e2ee = true;
         
     | 
| 
      
 2331 
     | 
    
         
            +
                  return answer;
         
     | 
| 
      
 2332 
     | 
    
         
            +
                }
         
     | 
| 
      
 2333 
     | 
    
         
            +
                function sendSDP(handleId, callbacks) {
         
     | 
| 
      
 2334 
     | 
    
         
            +
                  callbacks = callbacks || {};
         
     | 
| 
      
 2335 
     | 
    
         
            +
                  callbacks.success = typeof callbacks.success == "function" ? callbacks.success : Janus.noop;
         
     | 
| 
      
 2336 
     | 
    
         
            +
                  callbacks.error = typeof callbacks.error == "function" ? callbacks.error : Janus.noop;
         
     | 
| 
      
 2337 
     | 
    
         
            +
                  let pluginHandle = pluginHandles.get(handleId);
         
     | 
| 
      
 2338 
     | 
    
         
            +
                  if (!pluginHandle || !pluginHandle.webrtcStuff) {
         
     | 
| 
      
 2339 
     | 
    
         
            +
                    Janus.warn("Invalid handle, not sending anything");
         
     | 
| 
      
 2340 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 2341 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2342 
     | 
    
         
            +
                  let config = pluginHandle.webrtcStuff;
         
     | 
| 
      
 2343 
     | 
    
         
            +
                  Janus.log("Sending offer/answer SDP...");
         
     | 
| 
      
 2344 
     | 
    
         
            +
                  if (!config.mySdp) {
         
     | 
| 
      
 2345 
     | 
    
         
            +
                    Janus.warn("Local SDP instance is invalid, not sending anything...");
         
     | 
| 
      
 2346 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 2347 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2348 
     | 
    
         
            +
                  config.mySdp = {
         
     | 
| 
      
 2349 
     | 
    
         
            +
                    type: config.pc.localDescription.type,
         
     | 
| 
      
 2350 
     | 
    
         
            +
                    sdp: config.pc.localDescription.sdp
         
     | 
| 
      
 2351 
     | 
    
         
            +
                  };
         
     | 
| 
      
 2352 
     | 
    
         
            +
                  if (config.trickle === false) config.mySdp["trickle"] = false;
         
     | 
| 
      
 2353 
     | 
    
         
            +
                  Janus.debug(callbacks);
         
     | 
| 
      
 2354 
     | 
    
         
            +
                  config.sdpSent = true;
         
     | 
| 
      
 2355 
     | 
    
         
            +
                  callbacks.success(config.mySdp);
         
     | 
| 
      
 2356 
     | 
    
         
            +
                }
         
     | 
| 
      
 2357 
     | 
    
         
            +
                async function replaceTracks(handleId, callbacks) {
         
     | 
| 
      
 2358 
     | 
    
         
            +
                  callbacks = callbacks || {};
         
     | 
| 
      
 2359 
     | 
    
         
            +
                  callbacks.success = typeof callbacks.success == 'function' ? callbacks.success : Janus.noop;
         
     | 
| 
      
 2360 
     | 
    
         
            +
                  callbacks.error = typeof callbacks.error == 'function' ? callbacks.error : Janus.noop;
         
     | 
| 
      
 2361 
     | 
    
         
            +
                  // Check that callbacks.array is a valid array
         
     | 
| 
      
 2362 
     | 
    
         
            +
                  if (callbacks.tracks && !Array.isArray(callbacks.tracks)) {
         
     | 
| 
      
 2363 
     | 
    
         
            +
                    Janus.error('Tracks must be an array');
         
     | 
| 
      
 2364 
     | 
    
         
            +
                    callbacks.error('Tracks must be an array');
         
     | 
| 
      
 2365 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 2366 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2367 
     | 
    
         
            +
                  // Add the replace:true if it's missing
         
     | 
| 
      
 2368 
     | 
    
         
            +
                  for (let track of callbacks.tracks) {
         
     | 
| 
      
 2369 
     | 
    
         
            +
                    if (track.add || !track.replace && !track.remove) track.replace = true;
         
     | 
| 
      
 2370 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2371 
     | 
    
         
            +
                  try {
         
     | 
| 
      
 2372 
     | 
    
         
            +
                    await captureDevices(handleId, callbacks);
         
     | 
| 
      
 2373 
     | 
    
         
            +
                    callbacks.success();
         
     | 
| 
      
 2374 
     | 
    
         
            +
                  } catch (err) {
         
     | 
| 
      
 2375 
     | 
    
         
            +
                    Janus.error(err);
         
     | 
| 
      
 2376 
     | 
    
         
            +
                    callbacks.error(err);
         
     | 
| 
      
 2377 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2378 
     | 
    
         
            +
                }
         
     | 
| 
      
 2379 
     | 
    
         
            +
                async function captureDevices(handleId, callbacks) {
         
     | 
| 
      
 2380 
     | 
    
         
            +
                  let pluginHandle = pluginHandles.get(handleId);
         
     | 
| 
      
 2381 
     | 
    
         
            +
                  if (!pluginHandle || !pluginHandle.webrtcStuff) {
         
     | 
| 
      
 2382 
     | 
    
         
            +
                    Janus.warn('Invalid handle, not sending anything');
         
     | 
| 
      
 2383 
     | 
    
         
            +
                    throw 'Invalid handle';
         
     | 
| 
      
 2384 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2385 
     | 
    
         
            +
                  let config = pluginHandle.webrtcStuff;
         
     | 
| 
      
 2386 
     | 
    
         
            +
                  if (!config.pc) {
         
     | 
| 
      
 2387 
     | 
    
         
            +
                    Janus.warn('Invalid PeerConnection');
         
     | 
| 
      
 2388 
     | 
    
         
            +
                    throw 'Invalid PeerConnection';
         
     | 
| 
      
 2389 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2390 
     | 
    
         
            +
                  let tracks = callbacks.tracks;
         
     | 
| 
      
 2391 
     | 
    
         
            +
                  if (!tracks || !Array.isArray(tracks) || tracks.length === 0) {
         
     | 
| 
      
 2392 
     | 
    
         
            +
                    // Nothing to do
         
     | 
| 
      
 2393 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 2394 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2395 
     | 
    
         
            +
                  let openedConsentDialog = false;
         
     | 
| 
      
 2396 
     | 
    
         
            +
                  // Check if we can/should group getUserMedia calls
         
     | 
| 
      
 2397 
     | 
    
         
            +
                  let groups = {};
         
     | 
| 
      
 2398 
     | 
    
         
            +
                  for (let track of tracks) {
         
     | 
| 
      
 2399 
     | 
    
         
            +
                    delete track.gumGroup;
         
     | 
| 
      
 2400 
     | 
    
         
            +
                    if (!track.type || !['audio', 'video'].includes(track.type)) continue;
         
     | 
| 
      
 2401 
     | 
    
         
            +
                    if (!track.capture || track.capture instanceof MediaStreamTrack) continue;
         
     | 
| 
      
 2402 
     | 
    
         
            +
                    let group = track.group ? track.group : 'default';
         
     | 
| 
      
 2403 
     | 
    
         
            +
                    if (!groups[group]) groups[group] = {};
         
     | 
| 
      
 2404 
     | 
    
         
            +
                    if (groups[group][track.type]) continue;
         
     | 
| 
      
 2405 
     | 
    
         
            +
                    track.gumGroup = group;
         
     | 
| 
      
 2406 
     | 
    
         
            +
                    groups[group][track.type] = track;
         
     | 
| 
      
 2407 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2408 
     | 
    
         
            +
                  let keys = Object.keys(groups);
         
     | 
| 
      
 2409 
     | 
    
         
            +
                  for (let key of keys) {
         
     | 
| 
      
 2410 
     | 
    
         
            +
                    let group = groups[key];
         
     | 
| 
      
 2411 
     | 
    
         
            +
                    if (!group.audio || !group.video) {
         
     | 
| 
      
 2412 
     | 
    
         
            +
                      if (group.audio) delete group.audio.gumGroup;
         
     | 
| 
      
 2413 
     | 
    
         
            +
                      if (group.video) delete group.video.gumGroup;
         
     | 
| 
      
 2414 
     | 
    
         
            +
                      delete groups[key];
         
     | 
| 
      
 2415 
     | 
    
         
            +
                    }
         
     | 
| 
      
 2416 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2417 
     | 
    
         
            +
                  let answer = callbacks.jsep ? true : false;
         
     | 
| 
      
 2418 
     | 
    
         
            +
                  for (let track of tracks) {
         
     | 
| 
      
 2419 
     | 
    
         
            +
                    if (!track.type) {
         
     | 
| 
      
 2420 
     | 
    
         
            +
                      Janus.warn('Missing track type:', track);
         
     | 
| 
      
 2421 
     | 
    
         
            +
                      continue;
         
     | 
| 
      
 2422 
     | 
    
         
            +
                    }
         
     | 
| 
      
 2423 
     | 
    
         
            +
                    if (track.type === 'data') {
         
     | 
| 
      
 2424 
     | 
    
         
            +
                      // Easy enough: create a datachannel if we don't have one already
         
     | 
| 
      
 2425 
     | 
    
         
            +
                      if (config.pc.ondatachannel) {
         
     | 
| 
      
 2426 
     | 
    
         
            +
                        Janus.warn('Data channel exists already, not creating another one');
         
     | 
| 
      
 2427 
     | 
    
         
            +
                        continue;
         
     | 
| 
      
 2428 
     | 
    
         
            +
                      }
         
     | 
| 
      
 2429 
     | 
    
         
            +
                      Janus.log('Creating default data channel');
         
     | 
| 
      
 2430 
     | 
    
         
            +
                      createDataChannel(handleId, Janus.dataChanDefaultLabel, null, false);
         
     | 
| 
      
 2431 
     | 
    
         
            +
                      config.pc.ondatachannel = function (event) {
         
     | 
| 
      
 2432 
     | 
    
         
            +
                        Janus.log('Data channel created by Janus:', event);
         
     | 
| 
      
 2433 
     | 
    
         
            +
                        createDataChannel(handleId, event.channel.label, event.channel.protocol, event.channel);
         
     | 
| 
      
 2434 
     | 
    
         
            +
                      };
         
     | 
| 
      
 2435 
     | 
    
         
            +
                      continue;
         
     | 
| 
      
 2436 
     | 
    
         
            +
                    }
         
     | 
| 
      
 2437 
     | 
    
         
            +
                    if ((typeof track.add === 'undefined' || track.add === null) && (typeof track.remove === 'undefined' || track.remove === null) && (typeof track.replace === 'undefined' || track.replace === null)) {
         
     | 
| 
      
 2438 
     | 
    
         
            +
                      // Let's default to 'add'
         
     | 
| 
      
 2439 
     | 
    
         
            +
                      track.add = true;
         
     | 
| 
      
 2440 
     | 
    
         
            +
                    }
         
     | 
| 
      
 2441 
     | 
    
         
            +
                    if (track.add && track.remove || track.add && track.remove && track.replace) {
         
     | 
| 
      
 2442 
     | 
    
         
            +
                      Janus.warn('Conflicting actions for track, ignoring:', track);
         
     | 
| 
      
 2443 
     | 
    
         
            +
                      continue;
         
     | 
| 
      
 2444 
     | 
    
         
            +
                    }
         
     | 
| 
      
 2445 
     | 
    
         
            +
                    if (track.add && track.replace) {
         
     | 
| 
      
 2446 
     | 
    
         
            +
                      Janus.warn('Both add and replace provided, falling back to replace:', track);
         
     | 
| 
      
 2447 
     | 
    
         
            +
                      delete track.add;
         
     | 
| 
      
 2448 
     | 
    
         
            +
                    } else if (track.remove && track.replace) {
         
     | 
| 
      
 2449 
     | 
    
         
            +
                      Janus.warn('Both remove and replace provided, falling back to remove:', track);
         
     | 
| 
      
 2450 
     | 
    
         
            +
                      delete track.replace;
         
     | 
| 
      
 2451 
     | 
    
         
            +
                    }
         
     | 
| 
      
 2452 
     | 
    
         
            +
                    let kind = track.type;
         
     | 
| 
      
 2453 
     | 
    
         
            +
                    if (track.type === 'screen') kind = 'video'; // FIXME
         
     | 
| 
      
 2454 
     | 
    
         
            +
                    let transceiver = null,
         
     | 
| 
      
 2455 
     | 
    
         
            +
                      sender = null;
         
     | 
| 
      
 2456 
     | 
    
         
            +
                    if (track.mid) {
         
     | 
| 
      
 2457 
     | 
    
         
            +
                      // Search by mid
         
     | 
| 
      
 2458 
     | 
    
         
            +
                      transceiver = config.pc.getTransceivers().find(t => t.mid === track.mid && t.receiver.track.kind === kind);
         
     | 
| 
      
 2459 
     | 
    
         
            +
                    } else if (!track.add) {
         
     | 
| 
      
 2460 
     | 
    
         
            +
                      // Find the first track of this type
         
     | 
| 
      
 2461 
     | 
    
         
            +
                      transceiver = config.pc.getTransceivers().find(t => t.receiver.track.kind === kind);
         
     | 
| 
      
 2462 
     | 
    
         
            +
                    }
         
     | 
| 
      
 2463 
     | 
    
         
            +
                    if (track.replace || track.remove) {
         
     | 
| 
      
 2464 
     | 
    
         
            +
                      if (!transceiver) {
         
     | 
| 
      
 2465 
     | 
    
         
            +
                        Janus.warn("Couldn't find a transceiver for track:", track);
         
     | 
| 
      
 2466 
     | 
    
         
            +
                        continue;
         
     | 
| 
      
 2467 
     | 
    
         
            +
                      }
         
     | 
| 
      
 2468 
     | 
    
         
            +
                      if (!transceiver.sender) {
         
     | 
| 
      
 2469 
     | 
    
         
            +
                        Janus.warn('No sender in the transceiver for track:', track);
         
     | 
| 
      
 2470 
     | 
    
         
            +
                        continue;
         
     | 
| 
      
 2471 
     | 
    
         
            +
                      }
         
     | 
| 
      
 2472 
     | 
    
         
            +
                      sender = transceiver.sender;
         
     | 
| 
      
 2473 
     | 
    
         
            +
                    }
         
     | 
| 
      
 2474 
     | 
    
         
            +
                    if (answer && !transceiver) {
         
     | 
| 
      
 2475 
     | 
    
         
            +
                      transceiver = config.pc.getTransceivers().find(t => t.receiver.track.kind === kind);
         
     | 
| 
      
 2476 
     | 
    
         
            +
                      if (!transceiver) {
         
     | 
| 
      
 2477 
     | 
    
         
            +
                        Janus.warn("Couldn't find a transceiver for track:", track);
         
     | 
| 
      
 2478 
     | 
    
         
            +
                        continue;
         
     | 
| 
      
 2479 
     | 
    
         
            +
                      }
         
     | 
| 
      
 2480 
     | 
    
         
            +
                    }
         
     | 
| 
      
 2481 
     | 
    
         
            +
                    // Capture the new track, if we need to
         
     | 
| 
      
 2482 
     | 
    
         
            +
                    let nt = null,
         
     | 
| 
      
 2483 
     | 
    
         
            +
                      trackId = null;
         
     | 
| 
      
 2484 
     | 
    
         
            +
                    if (track.remove || track.replace) {
         
     | 
| 
      
 2485 
     | 
    
         
            +
                      Janus.log('Removing track from PeerConnection', track);
         
     | 
| 
      
 2486 
     | 
    
         
            +
                      trackId = sender.track ? sender.track.id : null;
         
     | 
| 
      
 2487 
     | 
    
         
            +
                      await sender.replaceTrack(null);
         
     | 
| 
      
 2488 
     | 
    
         
            +
                      // Get rid of the old track
         
     | 
| 
      
 2489 
     | 
    
         
            +
                      if (trackId && config.myStream) {
         
     | 
| 
      
 2490 
     | 
    
         
            +
                        let rt = null;
         
     | 
| 
      
 2491 
     | 
    
         
            +
                        if (kind === 'audio' && config.myStream.getAudioTracks() && config.myStream.getAudioTracks().length) {
         
     | 
| 
      
 2492 
     | 
    
         
            +
                          for (let t of config.myStream.getAudioTracks()) {
         
     | 
| 
      
 2493 
     | 
    
         
            +
                            if (t.id === trackId) {
         
     | 
| 
      
 2494 
     | 
    
         
            +
                              rt = t;
         
     | 
| 
      
 2495 
     | 
    
         
            +
                              Janus.log('Removing audio track:', rt);
         
     | 
| 
      
 2496 
     | 
    
         
            +
                            }
         
     | 
| 
      
 2497 
     | 
    
         
            +
                          }
         
     | 
| 
      
 2498 
     | 
    
         
            +
                        } else if (kind === 'video' && config.myStream.getVideoTracks() && config.myStream.getVideoTracks().length) {
         
     | 
| 
      
 2499 
     | 
    
         
            +
                          for (let t of config.myStream.getVideoTracks()) {
         
     | 
| 
      
 2500 
     | 
    
         
            +
                            if (t.id === trackId) {
         
     | 
| 
      
 2501 
     | 
    
         
            +
                              rt = t;
         
     | 
| 
      
 2502 
     | 
    
         
            +
                              Janus.log('Removing video track:', rt);
         
     | 
| 
      
 2503 
     | 
    
         
            +
                            }
         
     | 
| 
      
 2504 
     | 
    
         
            +
                          }
         
     | 
| 
      
 2505 
     | 
    
         
            +
                        }
         
     | 
| 
      
 2506 
     | 
    
         
            +
                        if (rt) {
         
     | 
| 
      
 2507 
     | 
    
         
            +
                          // Remove the track and notify the application
         
     | 
| 
      
 2508 
     | 
    
         
            +
                          try {
         
     | 
| 
      
 2509 
     | 
    
         
            +
                            config.myStream.removeTrack(rt);
         
     | 
| 
      
 2510 
     | 
    
         
            +
                            pluginHandle.onlocaltrack(rt, false);
         
     | 
| 
      
 2511 
     | 
    
         
            +
                          } catch (e) {
         
     | 
| 
      
 2512 
     | 
    
         
            +
                            Janus.error("Error calling onlocaltrack on removal for renegotiation", e);
         
     | 
| 
      
 2513 
     | 
    
         
            +
                          }
         
     | 
| 
      
 2514 
     | 
    
         
            +
                          // Close the old track (unless we've been asked not to)
         
     | 
| 
      
 2515 
     | 
    
         
            +
                          if (rt.dontStop !== true) {
         
     | 
| 
      
 2516 
     | 
    
         
            +
                            try {
         
     | 
| 
      
 2517 
     | 
    
         
            +
                              rt.stop();
         
     | 
| 
      
 2518 
     | 
    
         
            +
                              // eslint-disable-next-line no-unused-vars
         
     | 
| 
      
 2519 
     | 
    
         
            +
                            } catch (e) {}
         
     | 
| 
      
 2520 
     | 
    
         
            +
                          }
         
     | 
| 
      
 2521 
     | 
    
         
            +
                        }
         
     | 
| 
      
 2522 
     | 
    
         
            +
                      }
         
     | 
| 
      
 2523 
     | 
    
         
            +
                    }
         
     | 
| 
      
 2524 
     | 
    
         
            +
                    if (track.capture) {
         
     | 
| 
      
 2525 
     | 
    
         
            +
                      if (track.gumGroup && groups[track.gumGroup] && groups[track.gumGroup].stream) {
         
     | 
| 
      
 2526 
     | 
    
         
            +
                        // We did a getUserMedia before already
         
     | 
| 
      
 2527 
     | 
    
         
            +
                        let stream = groups[track.gumGroup].stream;
         
     | 
| 
      
 2528 
     | 
    
         
            +
                        nt = track.type === 'audio' ? stream.getAudioTracks()[0] : stream.getVideoTracks()[0];
         
     | 
| 
      
 2529 
     | 
    
         
            +
                        delete groups[track.gumGroup].stream;
         
     | 
| 
      
 2530 
     | 
    
         
            +
                        delete groups[track.gumGroup];
         
     | 
| 
      
 2531 
     | 
    
         
            +
                        delete track.gumGroup;
         
     | 
| 
      
 2532 
     | 
    
         
            +
                      } else if (track.capture instanceof MediaStreamTrack) {
         
     | 
| 
      
 2533 
     | 
    
         
            +
                        // An external track was provided, use that
         
     | 
| 
      
 2534 
     | 
    
         
            +
                        nt = track.capture;
         
     | 
| 
      
 2535 
     | 
    
         
            +
                      } else {
         
     | 
| 
      
 2536 
     | 
    
         
            +
                        if (!openedConsentDialog) {
         
     | 
| 
      
 2537 
     | 
    
         
            +
                          openedConsentDialog = true;
         
     | 
| 
      
 2538 
     | 
    
         
            +
                          pluginHandle.consentDialog(true);
         
     | 
| 
      
 2539 
     | 
    
         
            +
                        }
         
     | 
| 
      
 2540 
     | 
    
         
            +
                        let constraints = Janus.trackConstraints(track),
         
     | 
| 
      
 2541 
     | 
    
         
            +
                          stream = null;
         
     | 
| 
      
 2542 
     | 
    
         
            +
                        if (track.type === 'audio' || track.type === 'video') {
         
     | 
| 
      
 2543 
     | 
    
         
            +
                          // Use getUserMedia: check if we need to group audio and video together
         
     | 
| 
      
 2544 
     | 
    
         
            +
                          if (track.gumGroup) {
         
     | 
| 
      
 2545 
     | 
    
         
            +
                            let otherType = track.type === 'audio' ? 'video' : 'audio';
         
     | 
| 
      
 2546 
     | 
    
         
            +
                            if (groups[track.gumGroup] && groups[track.gumGroup][otherType]) {
         
     | 
| 
      
 2547 
     | 
    
         
            +
                              let otherTrack = groups[track.gumGroup][otherType];
         
     | 
| 
      
 2548 
     | 
    
         
            +
                              let otherConstraints = Janus.trackConstraints(otherTrack);
         
     | 
| 
      
 2549 
     | 
    
         
            +
                              constraints[otherType] = otherConstraints[otherType];
         
     | 
| 
      
 2550 
     | 
    
         
            +
                            }
         
     | 
| 
      
 2551 
     | 
    
         
            +
                          }
         
     | 
| 
      
 2552 
     | 
    
         
            +
                          stream = await navigator.mediaDevices.getUserMedia(constraints);
         
     | 
| 
      
 2553 
     | 
    
         
            +
                          if (track.gumGroup && constraints.audio && constraints.video) {
         
     | 
| 
      
 2554 
     | 
    
         
            +
                            // We just performed a grouped getUserMedia, keep track of the
         
     | 
| 
      
 2555 
     | 
    
         
            +
                            // stream so that we can immediately assign the track later
         
     | 
| 
      
 2556 
     | 
    
         
            +
                            groups[track.gumGroup].stream = stream;
         
     | 
| 
      
 2557 
     | 
    
         
            +
                            delete track.gumGroup;
         
     | 
| 
      
 2558 
     | 
    
         
            +
                          }
         
     | 
| 
      
 2559 
     | 
    
         
            +
                        } else {
         
     | 
| 
      
 2560 
     | 
    
         
            +
                          // Use getDisplayMedia
         
     | 
| 
      
 2561 
     | 
    
         
            +
                          stream = await navigator.mediaDevices.getDisplayMedia(constraints);
         
     | 
| 
      
 2562 
     | 
    
         
            +
                        }
         
     | 
| 
      
 2563 
     | 
    
         
            +
                        nt = track.type === 'audio' ? stream.getAudioTracks()[0] : stream.getVideoTracks()[0];
         
     | 
| 
      
 2564 
     | 
    
         
            +
                      }
         
     | 
| 
      
 2565 
     | 
    
         
            +
                      if (track.replace) {
         
     | 
| 
      
 2566 
     | 
    
         
            +
                        // Replace the track
         
     | 
| 
      
 2567 
     | 
    
         
            +
                        await sender.replaceTrack(nt);
         
     | 
| 
      
 2568 
     | 
    
         
            +
                        // Update the transceiver direction
         
     | 
| 
      
 2569 
     | 
    
         
            +
                        let newDirection = 'sendrecv';
         
     | 
| 
      
 2570 
     | 
    
         
            +
                        if (track.recv === false || transceiver.direction === 'inactive' || transceiver.direction === 'sendonly') newDirection = 'sendonly';
         
     | 
| 
      
 2571 
     | 
    
         
            +
                        if (transceiver.setDirection) transceiver.setDirection(newDirection);else transceiver.direction = newDirection;
         
     | 
| 
      
 2572 
     | 
    
         
            +
                      } else {
         
     | 
| 
      
 2573 
     | 
    
         
            +
                        // FIXME Add as a new track
         
     | 
| 
      
 2574 
     | 
    
         
            +
                        if (!config.myStream) config.myStream = new MediaStream();
         
     | 
| 
      
 2575 
     | 
    
         
            +
                        if (kind === 'audio' || !track.simulcast && !track.svc) {
         
     | 
| 
      
 2576 
     | 
    
         
            +
                          sender = config.pc.addTrack(nt, config.myStream);
         
     | 
| 
      
 2577 
     | 
    
         
            +
                          transceiver = config.pc.getTransceivers().find(t => t.sender === sender);
         
     | 
| 
      
 2578 
     | 
    
         
            +
                        } else if (track.simulcast) {
         
     | 
| 
      
 2579 
     | 
    
         
            +
                          if (Janus.webRTCAdapter.browserDetails.browser !== 'firefox') {
         
     | 
| 
      
 2580 
     | 
    
         
            +
                            // Standard RID
         
     | 
| 
      
 2581 
     | 
    
         
            +
                            Janus.log('Enabling rid-based simulcasting:', nt);
         
     | 
| 
      
 2582 
     | 
    
         
            +
                            let maxBitrates = getMaxBitrates(track.simulcastMaxBitrates);
         
     | 
| 
      
 2583 
     | 
    
         
            +
                            transceiver = config.pc.addTransceiver(nt, {
         
     | 
| 
      
 2584 
     | 
    
         
            +
                              direction: 'sendrecv',
         
     | 
| 
      
 2585 
     | 
    
         
            +
                              streams: [config.myStream],
         
     | 
| 
      
 2586 
     | 
    
         
            +
                              sendEncodings: track.sendEncodings || [{
         
     | 
| 
      
 2587 
     | 
    
         
            +
                                rid: 'h',
         
     | 
| 
      
 2588 
     | 
    
         
            +
                                active: true,
         
     | 
| 
      
 2589 
     | 
    
         
            +
                                scalabilityMode: 'L1T2',
         
     | 
| 
      
 2590 
     | 
    
         
            +
                                maxBitrate: maxBitrates.high
         
     | 
| 
      
 2591 
     | 
    
         
            +
                              }, {
         
     | 
| 
      
 2592 
     | 
    
         
            +
                                rid: 'm',
         
     | 
| 
      
 2593 
     | 
    
         
            +
                                active: true,
         
     | 
| 
      
 2594 
     | 
    
         
            +
                                scalabilityMode: 'L1T2',
         
     | 
| 
      
 2595 
     | 
    
         
            +
                                maxBitrate: maxBitrates.medium,
         
     | 
| 
      
 2596 
     | 
    
         
            +
                                scaleResolutionDownBy: 2
         
     | 
| 
      
 2597 
     | 
    
         
            +
                              }, {
         
     | 
| 
      
 2598 
     | 
    
         
            +
                                rid: 'l',
         
     | 
| 
      
 2599 
     | 
    
         
            +
                                active: true,
         
     | 
| 
      
 2600 
     | 
    
         
            +
                                scalabilityMode: 'L1T2',
         
     | 
| 
      
 2601 
     | 
    
         
            +
                                maxBitrate: maxBitrates.low,
         
     | 
| 
      
 2602 
     | 
    
         
            +
                                scaleResolutionDownBy: 4
         
     | 
| 
      
 2603 
     | 
    
         
            +
                              }]
         
     | 
| 
      
 2604 
     | 
    
         
            +
                            });
         
     | 
| 
      
 2605 
     | 
    
         
            +
                          } else {
         
     | 
| 
      
 2606 
     | 
    
         
            +
                            // Firefox-based RID, based on https://gist.github.com/voluntas/088bc3cc62094730647b
         
     | 
| 
      
 2607 
     | 
    
         
            +
                            Janus.log('Enabling Simulcasting for Firefox (RID)');
         
     | 
| 
      
 2608 
     | 
    
         
            +
                            transceiver = config.pc.addTransceiver(nt, {
         
     | 
| 
      
 2609 
     | 
    
         
            +
                              direction: 'sendrecv',
         
     | 
| 
      
 2610 
     | 
    
         
            +
                              streams: [config.myStream]
         
     | 
| 
      
 2611 
     | 
    
         
            +
                            });
         
     | 
| 
      
 2612 
     | 
    
         
            +
                            sender = transceiver ? transceiver.sender : null;
         
     | 
| 
      
 2613 
     | 
    
         
            +
                            if (sender) {
         
     | 
| 
      
 2614 
     | 
    
         
            +
                              let parameters = sender.getParameters();
         
     | 
| 
      
 2615 
     | 
    
         
            +
                              if (!parameters) parameters = {};
         
     | 
| 
      
 2616 
     | 
    
         
            +
                              let maxBitrates = getMaxBitrates(track.simulcastMaxBitrates);
         
     | 
| 
      
 2617 
     | 
    
         
            +
                              parameters.encodings = track.sendEncodings || [{
         
     | 
| 
      
 2618 
     | 
    
         
            +
                                rid: 'h',
         
     | 
| 
      
 2619 
     | 
    
         
            +
                                active: true,
         
     | 
| 
      
 2620 
     | 
    
         
            +
                                maxBitrate: maxBitrates.high
         
     | 
| 
      
 2621 
     | 
    
         
            +
                              }, {
         
     | 
| 
      
 2622 
     | 
    
         
            +
                                rid: 'm',
         
     | 
| 
      
 2623 
     | 
    
         
            +
                                active: true,
         
     | 
| 
      
 2624 
     | 
    
         
            +
                                maxBitrate: maxBitrates.medium,
         
     | 
| 
      
 2625 
     | 
    
         
            +
                                scaleResolutionDownBy: 2
         
     | 
| 
      
 2626 
     | 
    
         
            +
                              }, {
         
     | 
| 
      
 2627 
     | 
    
         
            +
                                rid: 'l',
         
     | 
| 
      
 2628 
     | 
    
         
            +
                                active: true,
         
     | 
| 
      
 2629 
     | 
    
         
            +
                                maxBitrate: maxBitrates.low,
         
     | 
| 
      
 2630 
     | 
    
         
            +
                                scaleResolutionDownBy: 4
         
     | 
| 
      
 2631 
     | 
    
         
            +
                              }];
         
     | 
| 
      
 2632 
     | 
    
         
            +
                              sender.setParameters(parameters);
         
     | 
| 
      
 2633 
     | 
    
         
            +
                            }
         
     | 
| 
      
 2634 
     | 
    
         
            +
                          }
         
     | 
| 
      
 2635 
     | 
    
         
            +
                        } else {
         
     | 
| 
      
 2636 
     | 
    
         
            +
                          Janus.log('Enabling SVC (' + track.svc + '):', nt);
         
     | 
| 
      
 2637 
     | 
    
         
            +
                          transceiver = config.pc.addTransceiver(nt, {
         
     | 
| 
      
 2638 
     | 
    
         
            +
                            direction: 'sendrecv',
         
     | 
| 
      
 2639 
     | 
    
         
            +
                            streams: [config.myStream],
         
     | 
| 
      
 2640 
     | 
    
         
            +
                            sendEncodings: [{
         
     | 
| 
      
 2641 
     | 
    
         
            +
                              scalabilityMode: track.svc
         
     | 
| 
      
 2642 
     | 
    
         
            +
                            }]
         
     | 
| 
      
 2643 
     | 
    
         
            +
                          });
         
     | 
| 
      
 2644 
     | 
    
         
            +
                        }
         
     | 
| 
      
 2645 
     | 
    
         
            +
                        if (!sender) sender = transceiver ? transceiver.sender : null;
         
     | 
| 
      
 2646 
     | 
    
         
            +
                        // Check if we need to override some settings
         
     | 
| 
      
 2647 
     | 
    
         
            +
                        if (track.codec) {
         
     | 
| 
      
 2648 
     | 
    
         
            +
                          if (Janus.webRTCAdapter.browserDetails.browser === 'firefox') {
         
     | 
| 
      
 2649 
     | 
    
         
            +
                            Janus.warn('setCodecPreferences not supported in Firefox, ignoring codec for track:', track);
         
     | 
| 
      
 2650 
     | 
    
         
            +
                          } else if (typeof track.codec !== 'string') {
         
     | 
| 
      
 2651 
     | 
    
         
            +
                            Janus.warn('Invalid codec value, ignoring for track:', track);
         
     | 
| 
      
 2652 
     | 
    
         
            +
                          } else {
         
     | 
| 
      
 2653 
     | 
    
         
            +
                            let mimeType = kind + '/' + track.codec.toLowerCase();
         
     | 
| 
      
 2654 
     | 
    
         
            +
                            let codecs = RTCRtpReceiver.getCapabilities(kind).codecs.filter(function (codec) {
         
     | 
| 
      
 2655 
     | 
    
         
            +
                              return codec.mimeType.toLowerCase() === mimeType;
         
     | 
| 
      
 2656 
     | 
    
         
            +
                            });
         
     | 
| 
      
 2657 
     | 
    
         
            +
                            if (!codecs || codecs.length === 0) {
         
     | 
| 
      
 2658 
     | 
    
         
            +
                              Janus.warn('Codec not supported in this browser for this track, ignoring:', track);
         
     | 
| 
      
 2659 
     | 
    
         
            +
                            } else if (transceiver) {
         
     | 
| 
      
 2660 
     | 
    
         
            +
                              try {
         
     | 
| 
      
 2661 
     | 
    
         
            +
                                transceiver.setCodecPreferences(codecs);
         
     | 
| 
      
 2662 
     | 
    
         
            +
                              } catch (err) {
         
     | 
| 
      
 2663 
     | 
    
         
            +
                                Janus.warn('Failed enforcing codec for this ' + kind + ' track:', err);
         
     | 
| 
      
 2664 
     | 
    
         
            +
                              }
         
     | 
| 
      
 2665 
     | 
    
         
            +
                            }
         
     | 
| 
      
 2666 
     | 
    
         
            +
                          }
         
     | 
| 
      
 2667 
     | 
    
         
            +
                        }
         
     | 
| 
      
 2668 
     | 
    
         
            +
                        if (track.bitrate) {
         
     | 
| 
      
 2669 
     | 
    
         
            +
                          // Override maximum bitrate
         
     | 
| 
      
 2670 
     | 
    
         
            +
                          if (track.simulcast || track.svc) {
         
     | 
| 
      
 2671 
     | 
    
         
            +
                            Janus.warn('Ignoring bitrate for simulcast/SVC track, use sendEncodings for that');
         
     | 
| 
      
 2672 
     | 
    
         
            +
                          } else if (isNaN(track.bitrate) || track.bitrate < 0) {
         
     | 
| 
      
 2673 
     | 
    
         
            +
                            Janus.warn('Ignoring invalid bitrate for track:', track);
         
     | 
| 
      
 2674 
     | 
    
         
            +
                          } else if (sender) {
         
     | 
| 
      
 2675 
     | 
    
         
            +
                            let params = sender.getParameters();
         
     | 
| 
      
 2676 
     | 
    
         
            +
                            if (!params || !params.encodings || params.encodings.length === 0) {
         
     | 
| 
      
 2677 
     | 
    
         
            +
                              Janus.warn('No encodings in the sender parameters, ignoring bitrate for track:', track);
         
     | 
| 
      
 2678 
     | 
    
         
            +
                            } else {
         
     | 
| 
      
 2679 
     | 
    
         
            +
                              params.encodings[0].maxBitrate = track.bitrate;
         
     | 
| 
      
 2680 
     | 
    
         
            +
                              await sender.setParameters(params);
         
     | 
| 
      
 2681 
     | 
    
         
            +
                            }
         
     | 
| 
      
 2682 
     | 
    
         
            +
                          }
         
     | 
| 
      
 2683 
     | 
    
         
            +
                        }
         
     | 
| 
      
 2684 
     | 
    
         
            +
                        if (kind === 'video' && track.framerate) {
         
     | 
| 
      
 2685 
     | 
    
         
            +
                          // Override maximum framerate
         
     | 
| 
      
 2686 
     | 
    
         
            +
                          if (track.simulcast || track.svc) {
         
     | 
| 
      
 2687 
     | 
    
         
            +
                            Janus.warn('Ignoring framerate for simulcast/SVC track, use sendEncodings for that');
         
     | 
| 
      
 2688 
     | 
    
         
            +
                          } else if (isNaN(track.framerate) || track.framerate < 0) {
         
     | 
| 
      
 2689 
     | 
    
         
            +
                            Janus.warn('Ignoring invalid framerate for track:', track);
         
     | 
| 
      
 2690 
     | 
    
         
            +
                          } else if (sender) {
         
     | 
| 
      
 2691 
     | 
    
         
            +
                            let params = sender.getParameters();
         
     | 
| 
      
 2692 
     | 
    
         
            +
                            if (!params || !params.encodings || params.encodings.length === 0) {
         
     | 
| 
      
 2693 
     | 
    
         
            +
                              Janus.warn('No encodings in the sender parameters, ignoring framerate for track:', track);
         
     | 
| 
      
 2694 
     | 
    
         
            +
                            } else {
         
     | 
| 
      
 2695 
     | 
    
         
            +
                              params.encodings[0].maxFramerate = track.framerate;
         
     | 
| 
      
 2696 
     | 
    
         
            +
                              await sender.setParameters(params);
         
     | 
| 
      
 2697 
     | 
    
         
            +
                            }
         
     | 
| 
      
 2698 
     | 
    
         
            +
                          }
         
     | 
| 
      
 2699 
     | 
    
         
            +
                        }
         
     | 
| 
      
 2700 
     | 
    
         
            +
                        // Check if insertable streams are involved
         
     | 
| 
      
 2701 
     | 
    
         
            +
                        if (track.transforms) {
         
     | 
| 
      
 2702 
     | 
    
         
            +
                          if (sender && track.transforms.sender) {
         
     | 
| 
      
 2703 
     | 
    
         
            +
                            // There's a sender transform, set it on the transceiver sender
         
     | 
| 
      
 2704 
     | 
    
         
            +
                            let senderStreams = null;
         
     | 
| 
      
 2705 
     | 
    
         
            +
                            if (RTCRtpSender.prototype.createEncodedStreams) {
         
     | 
| 
      
 2706 
     | 
    
         
            +
                              senderStreams = sender.createEncodedStreams();
         
     | 
| 
      
 2707 
     | 
    
         
            +
                            } else if (RTCRtpSender.prototype.createAudioEncodedStreams || RTCRtpSender.prototype.createEncodedVideoStreams) {
         
     | 
| 
      
 2708 
     | 
    
         
            +
                              if (kind === 'audio') {
         
     | 
| 
      
 2709 
     | 
    
         
            +
                                senderStreams = sender.createEncodedAudioStreams();
         
     | 
| 
      
 2710 
     | 
    
         
            +
                              } else if (kind === 'video') {
         
     | 
| 
      
 2711 
     | 
    
         
            +
                                senderStreams = sender.createEncodedVideoStreams();
         
     | 
| 
      
 2712 
     | 
    
         
            +
                              }
         
     | 
| 
      
 2713 
     | 
    
         
            +
                            }
         
     | 
| 
      
 2714 
     | 
    
         
            +
                            if (senderStreams) {
         
     | 
| 
      
 2715 
     | 
    
         
            +
                              if (senderStreams.readableStream && senderStreams.writableStream) {
         
     | 
| 
      
 2716 
     | 
    
         
            +
                                senderStreams.readableStream.pipeThrough(track.transforms.sender).pipeTo(senderStreams.writableStream);
         
     | 
| 
      
 2717 
     | 
    
         
            +
                              } else if (senderStreams.readable && senderStreams.writable) {
         
     | 
| 
      
 2718 
     | 
    
         
            +
                                senderStreams.readable.pipeThrough(track.transforms.sender).pipeTo(senderStreams.writable);
         
     | 
| 
      
 2719 
     | 
    
         
            +
                              }
         
     | 
| 
      
 2720 
     | 
    
         
            +
                            }
         
     | 
| 
      
 2721 
     | 
    
         
            +
                          }
         
     | 
| 
      
 2722 
     | 
    
         
            +
                          if (transceiver && transceiver.receiver && track.transforms.receiver) {
         
     | 
| 
      
 2723 
     | 
    
         
            +
                            // There's a receiver transform, set it on the transceiver receiver
         
     | 
| 
      
 2724 
     | 
    
         
            +
                            let receiverStreams = null;
         
     | 
| 
      
 2725 
     | 
    
         
            +
                            if (RTCRtpReceiver.prototype.createEncodedStreams) {
         
     | 
| 
      
 2726 
     | 
    
         
            +
                              receiverStreams = transceiver.receiver.createEncodedStreams();
         
     | 
| 
      
 2727 
     | 
    
         
            +
                            } else if (RTCRtpReceiver.prototype.createAudioEncodedStreams || RTCRtpReceiver.prototype.createEncodedVideoStreams) {
         
     | 
| 
      
 2728 
     | 
    
         
            +
                              if (kind === 'audio') {
         
     | 
| 
      
 2729 
     | 
    
         
            +
                                receiverStreams = transceiver.receiver.createEncodedAudioStreams();
         
     | 
| 
      
 2730 
     | 
    
         
            +
                              } else if (kind === 'video') {
         
     | 
| 
      
 2731 
     | 
    
         
            +
                                receiverStreams = transceiver.receiver.createEncodedVideoStreams();
         
     | 
| 
      
 2732 
     | 
    
         
            +
                              }
         
     | 
| 
      
 2733 
     | 
    
         
            +
                            }
         
     | 
| 
      
 2734 
     | 
    
         
            +
                            if (receiverStreams) {
         
     | 
| 
      
 2735 
     | 
    
         
            +
                              if (receiverStreams.readableStream && receiverStreams.writableStream) {
         
     | 
| 
      
 2736 
     | 
    
         
            +
                                receiverStreams.readableStream.pipeThrough(track.transforms.receiver).pipeTo(receiverStreams.writableStream);
         
     | 
| 
      
 2737 
     | 
    
         
            +
                              } else if (receiverStreams.readable && receiverStreams.writable) {
         
     | 
| 
      
 2738 
     | 
    
         
            +
                                receiverStreams.readable.pipeThrough(track.transforms.receiver).pipeTo(receiverStreams.writable);
         
     | 
| 
      
 2739 
     | 
    
         
            +
                              }
         
     | 
| 
      
 2740 
     | 
    
         
            +
                            }
         
     | 
| 
      
 2741 
     | 
    
         
            +
                          }
         
     | 
| 
      
 2742 
     | 
    
         
            +
                        }
         
     | 
| 
      
 2743 
     | 
    
         
            +
                      }
         
     | 
| 
      
 2744 
     | 
    
         
            +
                      if (nt && track.dontStop === true) nt.dontStop = true;
         
     | 
| 
      
 2745 
     | 
    
         
            +
                    } else if (track.recv) {
         
     | 
| 
      
 2746 
     | 
    
         
            +
                      // Maybe a new recvonly track
         
     | 
| 
      
 2747 
     | 
    
         
            +
                      if (!transceiver) transceiver = config.pc.addTransceiver(kind);
         
     | 
| 
      
 2748 
     | 
    
         
            +
                      if (transceiver) {
         
     | 
| 
      
 2749 
     | 
    
         
            +
                        // Check if we need to override some settings
         
     | 
| 
      
 2750 
     | 
    
         
            +
                        if (track.codec) {
         
     | 
| 
      
 2751 
     | 
    
         
            +
                          if (Janus.webRTCAdapter.browserDetails.browser === 'firefox') {
         
     | 
| 
      
 2752 
     | 
    
         
            +
                            Janus.warn('setCodecPreferences not supported in Firefox, ignoring codec for track:', track);
         
     | 
| 
      
 2753 
     | 
    
         
            +
                          } else if (typeof track.codec !== 'string') {
         
     | 
| 
      
 2754 
     | 
    
         
            +
                            Janus.warn('Invalid codec value, ignoring for track:', track);
         
     | 
| 
      
 2755 
     | 
    
         
            +
                          } else {
         
     | 
| 
      
 2756 
     | 
    
         
            +
                            let mimeType = kind + '/' + track.codec.toLowerCase();
         
     | 
| 
      
 2757 
     | 
    
         
            +
                            let codecs = RTCRtpReceiver.getCapabilities(kind).codecs.filter(function (codec) {
         
     | 
| 
      
 2758 
     | 
    
         
            +
                              return codec.mimeType.toLowerCase() === mimeType;
         
     | 
| 
      
 2759 
     | 
    
         
            +
                            });
         
     | 
| 
      
 2760 
     | 
    
         
            +
                            if (!codecs || codecs.length === 0) {
         
     | 
| 
      
 2761 
     | 
    
         
            +
                              Janus.warn('Codec not supported in this browser for this track, ignoring:', track);
         
     | 
| 
      
 2762 
     | 
    
         
            +
                            } else {
         
     | 
| 
      
 2763 
     | 
    
         
            +
                              try {
         
     | 
| 
      
 2764 
     | 
    
         
            +
                                transceiver.setCodecPreferences(codecs);
         
     | 
| 
      
 2765 
     | 
    
         
            +
                              } catch (err) {
         
     | 
| 
      
 2766 
     | 
    
         
            +
                                Janus.warn('Failed enforcing codec for this ' + kind + ' track:', err);
         
     | 
| 
      
 2767 
     | 
    
         
            +
                              }
         
     | 
| 
      
 2768 
     | 
    
         
            +
                            }
         
     | 
| 
      
 2769 
     | 
    
         
            +
                          }
         
     | 
| 
      
 2770 
     | 
    
         
            +
                        }
         
     | 
| 
      
 2771 
     | 
    
         
            +
                        // Check if insertable streams are involved
         
     | 
| 
      
 2772 
     | 
    
         
            +
                        if (transceiver.receiver && track.transforms && track.transforms.receiver) {
         
     | 
| 
      
 2773 
     | 
    
         
            +
                          // There's a receiver transform, set it on the transceiver receiver
         
     | 
| 
      
 2774 
     | 
    
         
            +
                          let receiverStreams = null;
         
     | 
| 
      
 2775 
     | 
    
         
            +
                          if (RTCRtpReceiver.prototype.createEncodedStreams) {
         
     | 
| 
      
 2776 
     | 
    
         
            +
                            receiverStreams = transceiver.receiver.createEncodedStreams();
         
     | 
| 
      
 2777 
     | 
    
         
            +
                          } else if (RTCRtpReceiver.prototype.createAudioEncodedStreams || RTCRtpReceiver.prototype.createEncodedVideoStreams) {
         
     | 
| 
      
 2778 
     | 
    
         
            +
                            if (kind === 'audio') {
         
     | 
| 
      
 2779 
     | 
    
         
            +
                              receiverStreams = transceiver.receiver.createEncodedAudioStreams();
         
     | 
| 
      
 2780 
     | 
    
         
            +
                            } else if (kind === 'video') {
         
     | 
| 
      
 2781 
     | 
    
         
            +
                              receiverStreams = transceiver.receiver.createEncodedVideoStreams();
         
     | 
| 
      
 2782 
     | 
    
         
            +
                            }
         
     | 
| 
      
 2783 
     | 
    
         
            +
                          }
         
     | 
| 
      
 2784 
     | 
    
         
            +
                          if (receiverStreams) {
         
     | 
| 
      
 2785 
     | 
    
         
            +
                            if (receiverStreams.readableStream && receiverStreams.writableStream) {
         
     | 
| 
      
 2786 
     | 
    
         
            +
                              receiverStreams.readableStream.pipeThrough(track.transforms.receiver).pipeTo(receiverStreams.writableStream);
         
     | 
| 
      
 2787 
     | 
    
         
            +
                            } else if (receiverStreams.readable && receiverStreams.writable) {
         
     | 
| 
      
 2788 
     | 
    
         
            +
                              receiverStreams.readable.pipeThrough(track.transforms.receiver).pipeTo(receiverStreams.writable);
         
     | 
| 
      
 2789 
     | 
    
         
            +
                            }
         
     | 
| 
      
 2790 
     | 
    
         
            +
                          }
         
     | 
| 
      
 2791 
     | 
    
         
            +
                        }
         
     | 
| 
      
 2792 
     | 
    
         
            +
                      }
         
     | 
| 
      
 2793 
     | 
    
         
            +
                    }
         
     | 
| 
      
 2794 
     | 
    
         
            +
                    if (nt) {
         
     | 
| 
      
 2795 
     | 
    
         
            +
                      // FIXME Add the new track locally
         
     | 
| 
      
 2796 
     | 
    
         
            +
                      config.myStream.addTrack(nt);
         
     | 
| 
      
 2797 
     | 
    
         
            +
                      // Notify the application about the new local track, if any
         
     | 
| 
      
 2798 
     | 
    
         
            +
                      nt.onended = function (ev) {
         
     | 
| 
      
 2799 
     | 
    
         
            +
                        Janus.log('Local track removed:', ev);
         
     | 
| 
      
 2800 
     | 
    
         
            +
                        try {
         
     | 
| 
      
 2801 
     | 
    
         
            +
                          pluginHandle.onlocaltrack(ev.target, false);
         
     | 
| 
      
 2802 
     | 
    
         
            +
                        } catch (e) {
         
     | 
| 
      
 2803 
     | 
    
         
            +
                          Janus.error("Error calling onlocaltrack following end", e);
         
     | 
| 
      
 2804 
     | 
    
         
            +
                        }
         
     | 
| 
      
 2805 
     | 
    
         
            +
                      };
         
     | 
| 
      
 2806 
     | 
    
         
            +
                      try {
         
     | 
| 
      
 2807 
     | 
    
         
            +
                        pluginHandle.onlocaltrack(nt, true);
         
     | 
| 
      
 2808 
     | 
    
         
            +
                      } catch (e) {
         
     | 
| 
      
 2809 
     | 
    
         
            +
                        Janus.error("Error calling onlocaltrack for track add", e);
         
     | 
| 
      
 2810 
     | 
    
         
            +
                      }
         
     | 
| 
      
 2811 
     | 
    
         
            +
                    }
         
     | 
| 
      
 2812 
     | 
    
         
            +
                    // Update the direction of the transceiver
         
     | 
| 
      
 2813 
     | 
    
         
            +
                    if (transceiver) {
         
     | 
| 
      
 2814 
     | 
    
         
            +
                      let curdir = transceiver.direction,
         
     | 
| 
      
 2815 
     | 
    
         
            +
                        newdir = null;
         
     | 
| 
      
 2816 
     | 
    
         
            +
                      let send = nt && transceiver.sender.track,
         
     | 
| 
      
 2817 
     | 
    
         
            +
                        recv = track.recv !== false && transceiver.receiver.track;
         
     | 
| 
      
 2818 
     | 
    
         
            +
                      if (send && recv) newdir = 'sendrecv';else if (send && !recv) newdir = 'sendonly';else if (!send && recv) newdir = 'recvonly';else if (!send && !recv) newdir = 'inactive';
         
     | 
| 
      
 2819 
     | 
    
         
            +
                      if (newdir && newdir !== curdir) {
         
     | 
| 
      
 2820 
     | 
    
         
            +
                        Janus.warn('Changing direction of transceiver to ' + newdir + ' (was ' + curdir + ')', track);
         
     | 
| 
      
 2821 
     | 
    
         
            +
                        if (transceiver.setDirection) transceiver.setDirection(newdir);else transceiver.direction = newdir;
         
     | 
| 
      
 2822 
     | 
    
         
            +
                      }
         
     | 
| 
      
 2823 
     | 
    
         
            +
                    }
         
     | 
| 
      
 2824 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2825 
     | 
    
         
            +
                  if (openedConsentDialog) pluginHandle.consentDialog(false);
         
     | 
| 
      
 2826 
     | 
    
         
            +
                }
         
     | 
| 
      
 2827 
     | 
    
         
            +
                function getLocalTracks(handleId) {
         
     | 
| 
      
 2828 
     | 
    
         
            +
                  let pluginHandle = pluginHandles.get(handleId);
         
     | 
| 
      
 2829 
     | 
    
         
            +
                  if (!pluginHandle || !pluginHandle.webrtcStuff) {
         
     | 
| 
      
 2830 
     | 
    
         
            +
                    Janus.warn('Invalid handle');
         
     | 
| 
      
 2831 
     | 
    
         
            +
                    return null;
         
     | 
| 
      
 2832 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2833 
     | 
    
         
            +
                  let config = pluginHandle.webrtcStuff;
         
     | 
| 
      
 2834 
     | 
    
         
            +
                  if (!config.pc) {
         
     | 
| 
      
 2835 
     | 
    
         
            +
                    Janus.warn('Invalid PeerConnection');
         
     | 
| 
      
 2836 
     | 
    
         
            +
                    return null;
         
     | 
| 
      
 2837 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2838 
     | 
    
         
            +
                  let tracks = [];
         
     | 
| 
      
 2839 
     | 
    
         
            +
                  let transceivers = config.pc.getTransceivers();
         
     | 
| 
      
 2840 
     | 
    
         
            +
                  for (let tr of transceivers) {
         
     | 
| 
      
 2841 
     | 
    
         
            +
                    let track = null;
         
     | 
| 
      
 2842 
     | 
    
         
            +
                    if (tr.sender && tr.sender.track) {
         
     | 
| 
      
 2843 
     | 
    
         
            +
                      track = {
         
     | 
| 
      
 2844 
     | 
    
         
            +
                        mid: tr.mid
         
     | 
| 
      
 2845 
     | 
    
         
            +
                      };
         
     | 
| 
      
 2846 
     | 
    
         
            +
                      track.type = tr.sender.track.kind;
         
     | 
| 
      
 2847 
     | 
    
         
            +
                      track.id = tr.sender.track.id;
         
     | 
| 
      
 2848 
     | 
    
         
            +
                      track.label = tr.sender.track.label;
         
     | 
| 
      
 2849 
     | 
    
         
            +
                    }
         
     | 
| 
      
 2850 
     | 
    
         
            +
                    if (track) tracks.push(track);
         
     | 
| 
      
 2851 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2852 
     | 
    
         
            +
                  return tracks;
         
     | 
| 
      
 2853 
     | 
    
         
            +
                }
         
     | 
| 
      
 2854 
     | 
    
         
            +
                function getRemoteTracks(handleId) {
         
     | 
| 
      
 2855 
     | 
    
         
            +
                  let pluginHandle = pluginHandles.get(handleId);
         
     | 
| 
      
 2856 
     | 
    
         
            +
                  if (!pluginHandle || !pluginHandle.webrtcStuff) {
         
     | 
| 
      
 2857 
     | 
    
         
            +
                    Janus.warn('Invalid handle');
         
     | 
| 
      
 2858 
     | 
    
         
            +
                    return null;
         
     | 
| 
      
 2859 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2860 
     | 
    
         
            +
                  let config = pluginHandle.webrtcStuff;
         
     | 
| 
      
 2861 
     | 
    
         
            +
                  if (!config.pc) {
         
     | 
| 
      
 2862 
     | 
    
         
            +
                    Janus.warn('Invalid PeerConnection');
         
     | 
| 
      
 2863 
     | 
    
         
            +
                    return null;
         
     | 
| 
      
 2864 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2865 
     | 
    
         
            +
                  let tracks = [];
         
     | 
| 
      
 2866 
     | 
    
         
            +
                  let transceivers = config.pc.getTransceivers();
         
     | 
| 
      
 2867 
     | 
    
         
            +
                  for (let tr of transceivers) {
         
     | 
| 
      
 2868 
     | 
    
         
            +
                    let track = null;
         
     | 
| 
      
 2869 
     | 
    
         
            +
                    if (tr.receiver && tr.receiver.track) {
         
     | 
| 
      
 2870 
     | 
    
         
            +
                      track = {
         
     | 
| 
      
 2871 
     | 
    
         
            +
                        mid: tr.mid
         
     | 
| 
      
 2872 
     | 
    
         
            +
                      };
         
     | 
| 
      
 2873 
     | 
    
         
            +
                      track.type = tr.receiver.track.kind;
         
     | 
| 
      
 2874 
     | 
    
         
            +
                      track.id = tr.receiver.track.id;
         
     | 
| 
      
 2875 
     | 
    
         
            +
                      track.label = tr.receiver.track.label;
         
     | 
| 
      
 2876 
     | 
    
         
            +
                    }
         
     | 
| 
      
 2877 
     | 
    
         
            +
                    if (track) tracks.push(track);
         
     | 
| 
      
 2878 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2879 
     | 
    
         
            +
                  return tracks;
         
     | 
| 
      
 2880 
     | 
    
         
            +
                }
         
     | 
| 
      
 2881 
     | 
    
         
            +
                function getVolume(handleId, mid, remote, result) {
         
     | 
| 
      
 2882 
     | 
    
         
            +
                  result = typeof result == "function" ? result : Janus.noop;
         
     | 
| 
      
 2883 
     | 
    
         
            +
                  let pluginHandle = pluginHandles.get(handleId);
         
     | 
| 
      
 2884 
     | 
    
         
            +
                  if (!pluginHandle || !pluginHandle.webrtcStuff) {
         
     | 
| 
      
 2885 
     | 
    
         
            +
                    Janus.warn("Invalid handle");
         
     | 
| 
      
 2886 
     | 
    
         
            +
                    result(0);
         
     | 
| 
      
 2887 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 2888 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2889 
     | 
    
         
            +
                  let stream = remote ? "remote" : "local";
         
     | 
| 
      
 2890 
     | 
    
         
            +
                  let config = pluginHandle.webrtcStuff;
         
     | 
| 
      
 2891 
     | 
    
         
            +
                  if (!config.volume[stream]) config.volume[stream] = {
         
     | 
| 
      
 2892 
     | 
    
         
            +
                    value: 0
         
     | 
| 
      
 2893 
     | 
    
         
            +
                  };
         
     | 
| 
      
 2894 
     | 
    
         
            +
                  // Start getting the volume, if audioLevel in getStats is supported (apparently
         
     | 
| 
      
 2895 
     | 
    
         
            +
                  // they're only available in Chrome/Safari right now: https://webrtc-stats.callstats.io/)
         
     | 
| 
      
 2896 
     | 
    
         
            +
                  if (config.pc && config.pc.getStats && (Janus.webRTCAdapter.browserDetails.browser === "chrome" || Janus.webRTCAdapter.browserDetails.browser === "safari")) {
         
     | 
| 
      
 2897 
     | 
    
         
            +
                    // Are we interested in a mid in particular?
         
     | 
| 
      
 2898 
     | 
    
         
            +
                    let query = config.pc;
         
     | 
| 
      
 2899 
     | 
    
         
            +
                    if (mid) {
         
     | 
| 
      
 2900 
     | 
    
         
            +
                      let transceiver = config.pc.getTransceivers().find(t => t.mid === mid && t.receiver.track.kind === "audio");
         
     | 
| 
      
 2901 
     | 
    
         
            +
                      if (!transceiver) {
         
     | 
| 
      
 2902 
     | 
    
         
            +
                        Janus.warn("No audio transceiver with mid " + mid);
         
     | 
| 
      
 2903 
     | 
    
         
            +
                        result(0);
         
     | 
| 
      
 2904 
     | 
    
         
            +
                        return;
         
     | 
| 
      
 2905 
     | 
    
         
            +
                      }
         
     | 
| 
      
 2906 
     | 
    
         
            +
                      if (remote && !transceiver.receiver) {
         
     | 
| 
      
 2907 
     | 
    
         
            +
                        Janus.warn("Remote transceiver track unavailable");
         
     | 
| 
      
 2908 
     | 
    
         
            +
                        result(0);
         
     | 
| 
      
 2909 
     | 
    
         
            +
                        return;
         
     | 
| 
      
 2910 
     | 
    
         
            +
                      } else if (!remote && !transceiver.sender) {
         
     | 
| 
      
 2911 
     | 
    
         
            +
                        Janus.warn("Local transceiver track unavailable");
         
     | 
| 
      
 2912 
     | 
    
         
            +
                        result(0);
         
     | 
| 
      
 2913 
     | 
    
         
            +
                        return;
         
     | 
| 
      
 2914 
     | 
    
         
            +
                      }
         
     | 
| 
      
 2915 
     | 
    
         
            +
                      query = remote ? transceiver.receiver : transceiver.sender;
         
     | 
| 
      
 2916 
     | 
    
         
            +
                    }
         
     | 
| 
      
 2917 
     | 
    
         
            +
                    query.getStats().then(function (stats) {
         
     | 
| 
      
 2918 
     | 
    
         
            +
                      stats.forEach(function (res) {
         
     | 
| 
      
 2919 
     | 
    
         
            +
                        if (!res || res.kind !== "audio") return;
         
     | 
| 
      
 2920 
     | 
    
         
            +
                        if (remote && !res.remoteSource || !remote && res.type !== "media-source") return;
         
     | 
| 
      
 2921 
     | 
    
         
            +
                        result(res.audioLevel ? res.audioLevel : 0);
         
     | 
| 
      
 2922 
     | 
    
         
            +
                      });
         
     | 
| 
      
 2923 
     | 
    
         
            +
                    });
         
     | 
| 
      
 2924 
     | 
    
         
            +
                    return config.volume[stream].value;
         
     | 
| 
      
 2925 
     | 
    
         
            +
                  } else {
         
     | 
| 
      
 2926 
     | 
    
         
            +
                    // audioInputLevel and audioOutputLevel seem only available in Chrome? audioLevel
         
     | 
| 
      
 2927 
     | 
    
         
            +
                    // seems to be available on Chrome and Firefox, but they don't seem to work
         
     | 
| 
      
 2928 
     | 
    
         
            +
                    Janus.warn("Getting the " + stream + " volume unsupported by browser");
         
     | 
| 
      
 2929 
     | 
    
         
            +
                    result(0);
         
     | 
| 
      
 2930 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 2931 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2932 
     | 
    
         
            +
                }
         
     | 
| 
      
 2933 
     | 
    
         
            +
                function isMuted(handleId, mid, video) {
         
     | 
| 
      
 2934 
     | 
    
         
            +
                  let pluginHandle = pluginHandles.get(handleId);
         
     | 
| 
      
 2935 
     | 
    
         
            +
                  if (!pluginHandle || !pluginHandle.webrtcStuff) {
         
     | 
| 
      
 2936 
     | 
    
         
            +
                    Janus.warn("Invalid handle");
         
     | 
| 
      
 2937 
     | 
    
         
            +
                    return true;
         
     | 
| 
      
 2938 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2939 
     | 
    
         
            +
                  let config = pluginHandle.webrtcStuff;
         
     | 
| 
      
 2940 
     | 
    
         
            +
                  if (!config.pc) {
         
     | 
| 
      
 2941 
     | 
    
         
            +
                    Janus.warn("Invalid PeerConnection");
         
     | 
| 
      
 2942 
     | 
    
         
            +
                    return true;
         
     | 
| 
      
 2943 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2944 
     | 
    
         
            +
                  if (!config.myStream) {
         
     | 
| 
      
 2945 
     | 
    
         
            +
                    Janus.warn("Invalid local MediaStream");
         
     | 
| 
      
 2946 
     | 
    
         
            +
                    return true;
         
     | 
| 
      
 2947 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2948 
     | 
    
         
            +
                  if (video) {
         
     | 
| 
      
 2949 
     | 
    
         
            +
                    // Check video track
         
     | 
| 
      
 2950 
     | 
    
         
            +
                    if (!config.myStream.getVideoTracks() || config.myStream.getVideoTracks().length === 0) {
         
     | 
| 
      
 2951 
     | 
    
         
            +
                      Janus.warn("No video track");
         
     | 
| 
      
 2952 
     | 
    
         
            +
                      return true;
         
     | 
| 
      
 2953 
     | 
    
         
            +
                    }
         
     | 
| 
      
 2954 
     | 
    
         
            +
                    if (mid) {
         
     | 
| 
      
 2955 
     | 
    
         
            +
                      let transceiver = config.pc.getTransceivers().find(t => t.mid === mid && t.receiver.track.kind === "video");
         
     | 
| 
      
 2956 
     | 
    
         
            +
                      if (!transceiver) {
         
     | 
| 
      
 2957 
     | 
    
         
            +
                        Janus.warn("No video transceiver with mid " + mid);
         
     | 
| 
      
 2958 
     | 
    
         
            +
                        return true;
         
     | 
| 
      
 2959 
     | 
    
         
            +
                      }
         
     | 
| 
      
 2960 
     | 
    
         
            +
                      if (!transceiver.sender || !transceiver.sender.track) {
         
     | 
| 
      
 2961 
     | 
    
         
            +
                        Janus.warn("No video sender with mid " + mid);
         
     | 
| 
      
 2962 
     | 
    
         
            +
                        return true;
         
     | 
| 
      
 2963 
     | 
    
         
            +
                      }
         
     | 
| 
      
 2964 
     | 
    
         
            +
                      return !transceiver.sender.track.enabled;
         
     | 
| 
      
 2965 
     | 
    
         
            +
                    } else {
         
     | 
| 
      
 2966 
     | 
    
         
            +
                      return !config.myStream.getVideoTracks()[0].enabled;
         
     | 
| 
      
 2967 
     | 
    
         
            +
                    }
         
     | 
| 
      
 2968 
     | 
    
         
            +
                  } else {
         
     | 
| 
      
 2969 
     | 
    
         
            +
                    // Check audio track
         
     | 
| 
      
 2970 
     | 
    
         
            +
                    if (!config.myStream.getAudioTracks() || config.myStream.getAudioTracks().length === 0) {
         
     | 
| 
      
 2971 
     | 
    
         
            +
                      Janus.warn("No audio track");
         
     | 
| 
      
 2972 
     | 
    
         
            +
                      return true;
         
     | 
| 
      
 2973 
     | 
    
         
            +
                    }
         
     | 
| 
      
 2974 
     | 
    
         
            +
                    if (mid) {
         
     | 
| 
      
 2975 
     | 
    
         
            +
                      let transceiver = config.pc.getTransceivers().find(t => t.mid === mid && t.receiver.track.kind === "audio");
         
     | 
| 
      
 2976 
     | 
    
         
            +
                      if (!transceiver) {
         
     | 
| 
      
 2977 
     | 
    
         
            +
                        Janus.warn("No audio transceiver with mid " + mid);
         
     | 
| 
      
 2978 
     | 
    
         
            +
                        return true;
         
     | 
| 
      
 2979 
     | 
    
         
            +
                      }
         
     | 
| 
      
 2980 
     | 
    
         
            +
                      if (!transceiver.sender || !transceiver.sender.track) {
         
     | 
| 
      
 2981 
     | 
    
         
            +
                        Janus.warn("No audio sender with mid " + mid);
         
     | 
| 
      
 2982 
     | 
    
         
            +
                        return true;
         
     | 
| 
      
 2983 
     | 
    
         
            +
                      }
         
     | 
| 
      
 2984 
     | 
    
         
            +
                      return !transceiver.sender.track.enabled;
         
     | 
| 
      
 2985 
     | 
    
         
            +
                    } else {
         
     | 
| 
      
 2986 
     | 
    
         
            +
                      return !config.myStream.getAudioTracks()[0].enabled;
         
     | 
| 
      
 2987 
     | 
    
         
            +
                    }
         
     | 
| 
      
 2988 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2989 
     | 
    
         
            +
                }
         
     | 
| 
      
 2990 
     | 
    
         
            +
                function mute(handleId, mid, video, mute) {
         
     | 
| 
      
 2991 
     | 
    
         
            +
                  let pluginHandle = pluginHandles.get(handleId);
         
     | 
| 
      
 2992 
     | 
    
         
            +
                  if (!pluginHandle || !pluginHandle.webrtcStuff) {
         
     | 
| 
      
 2993 
     | 
    
         
            +
                    Janus.warn("Invalid handle");
         
     | 
| 
      
 2994 
     | 
    
         
            +
                    return false;
         
     | 
| 
      
 2995 
     | 
    
         
            +
                  }
         
     | 
| 
      
 2996 
     | 
    
         
            +
                  let config = pluginHandle.webrtcStuff;
         
     | 
| 
      
 2997 
     | 
    
         
            +
                  if (!config.pc) {
         
     | 
| 
      
 2998 
     | 
    
         
            +
                    Janus.warn("Invalid PeerConnection");
         
     | 
| 
      
 2999 
     | 
    
         
            +
                    return false;
         
     | 
| 
      
 3000 
     | 
    
         
            +
                  }
         
     | 
| 
      
 3001 
     | 
    
         
            +
                  if (!config.myStream) {
         
     | 
| 
      
 3002 
     | 
    
         
            +
                    Janus.warn("Invalid local MediaStream");
         
     | 
| 
      
 3003 
     | 
    
         
            +
                    return false;
         
     | 
| 
      
 3004 
     | 
    
         
            +
                  }
         
     | 
| 
      
 3005 
     | 
    
         
            +
                  if (video) {
         
     | 
| 
      
 3006 
     | 
    
         
            +
                    // Mute/unmute video track
         
     | 
| 
      
 3007 
     | 
    
         
            +
                    if (!config.myStream.getVideoTracks() || config.myStream.getVideoTracks().length === 0) {
         
     | 
| 
      
 3008 
     | 
    
         
            +
                      Janus.warn("No video track");
         
     | 
| 
      
 3009 
     | 
    
         
            +
                      return false;
         
     | 
| 
      
 3010 
     | 
    
         
            +
                    }
         
     | 
| 
      
 3011 
     | 
    
         
            +
                    if (mid) {
         
     | 
| 
      
 3012 
     | 
    
         
            +
                      let transceiver = config.pc.getTransceivers().find(t => t.mid === mid && t.receiver.track.kind === "video");
         
     | 
| 
      
 3013 
     | 
    
         
            +
                      if (!transceiver) {
         
     | 
| 
      
 3014 
     | 
    
         
            +
                        Janus.warn("No video transceiver with mid " + mid);
         
     | 
| 
      
 3015 
     | 
    
         
            +
                        return false;
         
     | 
| 
      
 3016 
     | 
    
         
            +
                      }
         
     | 
| 
      
 3017 
     | 
    
         
            +
                      if (!transceiver.sender || !transceiver.sender.track) {
         
     | 
| 
      
 3018 
     | 
    
         
            +
                        Janus.warn("No video sender with mid " + mid);
         
     | 
| 
      
 3019 
     | 
    
         
            +
                        return false;
         
     | 
| 
      
 3020 
     | 
    
         
            +
                      }
         
     | 
| 
      
 3021 
     | 
    
         
            +
                      transceiver.sender.track.enabled = mute ? false : true;
         
     | 
| 
      
 3022 
     | 
    
         
            +
                    } else {
         
     | 
| 
      
 3023 
     | 
    
         
            +
                      for (const videostream of config.myStream.getVideoTracks()) {
         
     | 
| 
      
 3024 
     | 
    
         
            +
                        videostream.enabled = !mute;
         
     | 
| 
      
 3025 
     | 
    
         
            +
                      }
         
     | 
| 
      
 3026 
     | 
    
         
            +
                    }
         
     | 
| 
      
 3027 
     | 
    
         
            +
                  } else {
         
     | 
| 
      
 3028 
     | 
    
         
            +
                    // Mute/unmute audio track
         
     | 
| 
      
 3029 
     | 
    
         
            +
                    if (!config.myStream.getAudioTracks() || config.myStream.getAudioTracks().length === 0) {
         
     | 
| 
      
 3030 
     | 
    
         
            +
                      Janus.warn("No audio track");
         
     | 
| 
      
 3031 
     | 
    
         
            +
                      return false;
         
     | 
| 
      
 3032 
     | 
    
         
            +
                    }
         
     | 
| 
      
 3033 
     | 
    
         
            +
                    if (mid) {
         
     | 
| 
      
 3034 
     | 
    
         
            +
                      let transceiver = config.pc.getTransceivers().find(t => t.mid === mid && t.receiver.track.kind === "audio");
         
     | 
| 
      
 3035 
     | 
    
         
            +
                      if (!transceiver) {
         
     | 
| 
      
 3036 
     | 
    
         
            +
                        Janus.warn("No audio transceiver with mid " + mid);
         
     | 
| 
      
 3037 
     | 
    
         
            +
                        return false;
         
     | 
| 
      
 3038 
     | 
    
         
            +
                      }
         
     | 
| 
      
 3039 
     | 
    
         
            +
                      if (!transceiver.sender || !transceiver.sender.track) {
         
     | 
| 
      
 3040 
     | 
    
         
            +
                        Janus.warn("No audio sender with mid " + mid);
         
     | 
| 
      
 3041 
     | 
    
         
            +
                        return false;
         
     | 
| 
      
 3042 
     | 
    
         
            +
                      }
         
     | 
| 
      
 3043 
     | 
    
         
            +
                      transceiver.sender.track.enabled = mute ? false : true;
         
     | 
| 
      
 3044 
     | 
    
         
            +
                    } else {
         
     | 
| 
      
 3045 
     | 
    
         
            +
                      for (const audiostream of config.myStream.getAudioTracks()) {
         
     | 
| 
      
 3046 
     | 
    
         
            +
                        audiostream.enabled = !mute;
         
     | 
| 
      
 3047 
     | 
    
         
            +
                      }
         
     | 
| 
      
 3048 
     | 
    
         
            +
                    }
         
     | 
| 
      
 3049 
     | 
    
         
            +
                  }
         
     | 
| 
      
 3050 
     | 
    
         
            +
                  return true;
         
     | 
| 
      
 3051 
     | 
    
         
            +
                }
         
     | 
| 
      
 3052 
     | 
    
         
            +
                function getBitrate(handleId, mid) {
         
     | 
| 
      
 3053 
     | 
    
         
            +
                  let pluginHandle = pluginHandles.get(handleId);
         
     | 
| 
      
 3054 
     | 
    
         
            +
                  if (!pluginHandle || !pluginHandle.webrtcStuff) {
         
     | 
| 
      
 3055 
     | 
    
         
            +
                    Janus.warn("Invalid handle");
         
     | 
| 
      
 3056 
     | 
    
         
            +
                    return "Invalid handle";
         
     | 
| 
      
 3057 
     | 
    
         
            +
                  }
         
     | 
| 
      
 3058 
     | 
    
         
            +
                  let config = pluginHandle.webrtcStuff;
         
     | 
| 
      
 3059 
     | 
    
         
            +
                  if (!config.pc) return "Invalid PeerConnection";
         
     | 
| 
      
 3060 
     | 
    
         
            +
                  // Start getting the bitrate, if getStats is supported
         
     | 
| 
      
 3061 
     | 
    
         
            +
                  if (config.pc.getStats) {
         
     | 
| 
      
 3062 
     | 
    
         
            +
                    let query = config.pc;
         
     | 
| 
      
 3063 
     | 
    
         
            +
                    let target = mid ? mid : "default";
         
     | 
| 
      
 3064 
     | 
    
         
            +
                    if (mid) {
         
     | 
| 
      
 3065 
     | 
    
         
            +
                      let transceiver = config.pc.getTransceivers().find(t => t.mid === mid && t.receiver.track.kind === "video");
         
     | 
| 
      
 3066 
     | 
    
         
            +
                      if (!transceiver) {
         
     | 
| 
      
 3067 
     | 
    
         
            +
                        Janus.warn("No video transceiver with mid " + mid);
         
     | 
| 
      
 3068 
     | 
    
         
            +
                        return "No video transceiver with mid " + mid;
         
     | 
| 
      
 3069 
     | 
    
         
            +
                      }
         
     | 
| 
      
 3070 
     | 
    
         
            +
                      if (!transceiver.receiver) {
         
     | 
| 
      
 3071 
     | 
    
         
            +
                        Janus.warn("No video receiver with mid " + mid);
         
     | 
| 
      
 3072 
     | 
    
         
            +
                        return "No video receiver with mid " + mid;
         
     | 
| 
      
 3073 
     | 
    
         
            +
                      }
         
     | 
| 
      
 3074 
     | 
    
         
            +
                      query = transceiver.receiver;
         
     | 
| 
      
 3075 
     | 
    
         
            +
                    }
         
     | 
| 
      
 3076 
     | 
    
         
            +
                    if (!config.bitrate[target]) {
         
     | 
| 
      
 3077 
     | 
    
         
            +
                      config.bitrate[target] = {
         
     | 
| 
      
 3078 
     | 
    
         
            +
                        timer: null,
         
     | 
| 
      
 3079 
     | 
    
         
            +
                        bsnow: null,
         
     | 
| 
      
 3080 
     | 
    
         
            +
                        bsbefore: null,
         
     | 
| 
      
 3081 
     | 
    
         
            +
                        tsnow: null,
         
     | 
| 
      
 3082 
     | 
    
         
            +
                        tsbefore: null,
         
     | 
| 
      
 3083 
     | 
    
         
            +
                        value: "0 kbits/sec"
         
     | 
| 
      
 3084 
     | 
    
         
            +
                      };
         
     | 
| 
      
 3085 
     | 
    
         
            +
                    }
         
     | 
| 
      
 3086 
     | 
    
         
            +
                    if (!config.bitrate[target].timer) {
         
     | 
| 
      
 3087 
     | 
    
         
            +
                      Janus.log("Starting bitrate timer" + (mid ? " for mid " + mid : "") + " (via getStats)");
         
     | 
| 
      
 3088 
     | 
    
         
            +
                      config.bitrate[target].timer = setInterval(function () {
         
     | 
| 
      
 3089 
     | 
    
         
            +
                        query.getStats().then(function (stats) {
         
     | 
| 
      
 3090 
     | 
    
         
            +
                          stats.forEach(function (res) {
         
     | 
| 
      
 3091 
     | 
    
         
            +
                            if (!res) return;
         
     | 
| 
      
 3092 
     | 
    
         
            +
                            let inStats = false;
         
     | 
| 
      
 3093 
     | 
    
         
            +
                            // Check if these are statistics on incoming media
         
     | 
| 
      
 3094 
     | 
    
         
            +
                            if ((res.mediaType === "video" || res.kind === "video" || res.id.toLowerCase().indexOf("video") > -1) && res.type === "inbound-rtp" && res.id.indexOf("rtcp") < 0) {
         
     | 
| 
      
 3095 
     | 
    
         
            +
                              // New stats
         
     | 
| 
      
 3096 
     | 
    
         
            +
                              inStats = true;
         
     | 
| 
      
 3097 
     | 
    
         
            +
                            } else if (res.type == 'ssrc' && res.bytesReceived && (res.googCodecName === "VP8" || res.googCodecName === "")) {
         
     | 
| 
      
 3098 
     | 
    
         
            +
                              // Older Chromer versions
         
     | 
| 
      
 3099 
     | 
    
         
            +
                              inStats = true;
         
     | 
| 
      
 3100 
     | 
    
         
            +
                            }
         
     | 
| 
      
 3101 
     | 
    
         
            +
                            // Parse stats now
         
     | 
| 
      
 3102 
     | 
    
         
            +
                            if (inStats) {
         
     | 
| 
      
 3103 
     | 
    
         
            +
                              config.bitrate[target].bsnow = res.bytesReceived;
         
     | 
| 
      
 3104 
     | 
    
         
            +
                              config.bitrate[target].tsnow = res.timestamp;
         
     | 
| 
      
 3105 
     | 
    
         
            +
                              if (config.bitrate[target].bsbefore === null || config.bitrate[target].tsbefore === null) {
         
     | 
| 
      
 3106 
     | 
    
         
            +
                                // Skip this round
         
     | 
| 
      
 3107 
     | 
    
         
            +
                                config.bitrate[target].bsbefore = config.bitrate[target].bsnow;
         
     | 
| 
      
 3108 
     | 
    
         
            +
                                config.bitrate[target].tsbefore = config.bitrate[target].tsnow;
         
     | 
| 
      
 3109 
     | 
    
         
            +
                              } else {
         
     | 
| 
      
 3110 
     | 
    
         
            +
                                // Calculate bitrate
         
     | 
| 
      
 3111 
     | 
    
         
            +
                                let timePassed = config.bitrate[target].tsnow - config.bitrate[target].tsbefore;
         
     | 
| 
      
 3112 
     | 
    
         
            +
                                if (Janus.webRTCAdapter.browserDetails.browser === "safari") timePassed = timePassed / 1000; // Apparently the timestamp is in microseconds, in Safari
         
     | 
| 
      
 3113 
     | 
    
         
            +
                                let bitRate = Math.round((config.bitrate[target].bsnow - config.bitrate[target].bsbefore) * 8 / timePassed);
         
     | 
| 
      
 3114 
     | 
    
         
            +
                                if (Janus.webRTCAdapter.browserDetails.browser === "safari") bitRate = parseInt(bitRate / 1000);
         
     | 
| 
      
 3115 
     | 
    
         
            +
                                config.bitrate[target].value = bitRate + ' kbits/sec';
         
     | 
| 
      
 3116 
     | 
    
         
            +
                                //~ Janus.log("Estimated bitrate is " + config.bitrate.value);
         
     | 
| 
      
 3117 
     | 
    
         
            +
                                config.bitrate[target].bsbefore = config.bitrate[target].bsnow;
         
     | 
| 
      
 3118 
     | 
    
         
            +
                                config.bitrate[target].tsbefore = config.bitrate[target].tsnow;
         
     | 
| 
      
 3119 
     | 
    
         
            +
                              }
         
     | 
| 
      
 3120 
     | 
    
         
            +
                            }
         
     | 
| 
      
 3121 
     | 
    
         
            +
                          });
         
     | 
| 
      
 3122 
     | 
    
         
            +
                        });
         
     | 
| 
      
 3123 
     | 
    
         
            +
                      }, 1000);
         
     | 
| 
      
 3124 
     | 
    
         
            +
                      return "0 kbits/sec"; // We don't have a bitrate value yet
         
     | 
| 
      
 3125 
     | 
    
         
            +
                    }
         
     | 
| 
      
 3126 
     | 
    
         
            +
                    return config.bitrate[target].value;
         
     | 
| 
      
 3127 
     | 
    
         
            +
                  } else {
         
     | 
| 
      
 3128 
     | 
    
         
            +
                    Janus.warn("Getting the video bitrate unsupported by browser");
         
     | 
| 
      
 3129 
     | 
    
         
            +
                    return "Feature unsupported by browser";
         
     | 
| 
      
 3130 
     | 
    
         
            +
                  }
         
     | 
| 
      
 3131 
     | 
    
         
            +
                }
         
     | 
| 
      
 3132 
     | 
    
         
            +
                function setBitrate(handleId, mid, bitrate) {
         
     | 
| 
      
 3133 
     | 
    
         
            +
                  let pluginHandle = pluginHandles.get(handleId);
         
     | 
| 
      
 3134 
     | 
    
         
            +
                  if (!pluginHandle || !pluginHandle.webrtcStuff) {
         
     | 
| 
      
 3135 
     | 
    
         
            +
                    Janus.warn('Invalid handle');
         
     | 
| 
      
 3136 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 3137 
     | 
    
         
            +
                  }
         
     | 
| 
      
 3138 
     | 
    
         
            +
                  let config = pluginHandle.webrtcStuff;
         
     | 
| 
      
 3139 
     | 
    
         
            +
                  if (!config.pc) {
         
     | 
| 
      
 3140 
     | 
    
         
            +
                    Janus.warn('Invalid PeerConnection');
         
     | 
| 
      
 3141 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 3142 
     | 
    
         
            +
                  }
         
     | 
| 
      
 3143 
     | 
    
         
            +
                  let transceiver = config.pc.getTransceivers().find(t => t.mid === mid);
         
     | 
| 
      
 3144 
     | 
    
         
            +
                  if (!transceiver) {
         
     | 
| 
      
 3145 
     | 
    
         
            +
                    Janus.warn('No transceiver with mid', mid);
         
     | 
| 
      
 3146 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 3147 
     | 
    
         
            +
                  }
         
     | 
| 
      
 3148 
     | 
    
         
            +
                  if (!transceiver.sender) {
         
     | 
| 
      
 3149 
     | 
    
         
            +
                    Janus.warn('No sender for transceiver with mid', mid);
         
     | 
| 
      
 3150 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 3151 
     | 
    
         
            +
                  }
         
     | 
| 
      
 3152 
     | 
    
         
            +
                  let params = transceiver.sender.getParameters();
         
     | 
| 
      
 3153 
     | 
    
         
            +
                  if (!params || !params.encodings || params.encodings.length === 0) {
         
     | 
| 
      
 3154 
     | 
    
         
            +
                    Janus.warn('No parameters encodings');
         
     | 
| 
      
 3155 
     | 
    
         
            +
                  } else if (params.encodings.length > 1) {
         
     | 
| 
      
 3156 
     | 
    
         
            +
                    Janus.warn('Ignoring bitrate for simulcast track, use sendEncodings for that');
         
     | 
| 
      
 3157 
     | 
    
         
            +
                  } else if (isNaN(bitrate) || bitrate < 0) {
         
     | 
| 
      
 3158 
     | 
    
         
            +
                    Janus.warn('Invalid bitrate (must be a positive integer)');
         
     | 
| 
      
 3159 
     | 
    
         
            +
                  } else {
         
     | 
| 
      
 3160 
     | 
    
         
            +
                    params.encodings[0].maxBitrate = bitrate;
         
     | 
| 
      
 3161 
     | 
    
         
            +
                    transceiver.sender.setParameters(params);
         
     | 
| 
      
 3162 
     | 
    
         
            +
                  }
         
     | 
| 
      
 3163 
     | 
    
         
            +
                }
         
     | 
| 
      
 3164 
     | 
    
         
            +
                function webrtcError(error) {
         
     | 
| 
      
 3165 
     | 
    
         
            +
                  Janus.error("WebRTC error:", error);
         
     | 
| 
      
 3166 
     | 
    
         
            +
                }
         
     | 
| 
      
 3167 
     | 
    
         
            +
                function cleanupWebrtc(handleId, hangupRequest) {
         
     | 
| 
      
 3168 
     | 
    
         
            +
                  Janus.log("Cleaning WebRTC stuff");
         
     | 
| 
      
 3169 
     | 
    
         
            +
                  let pluginHandle = pluginHandles.get(handleId);
         
     | 
| 
      
 3170 
     | 
    
         
            +
                  if (!pluginHandle) {
         
     | 
| 
      
 3171 
     | 
    
         
            +
                    // Nothing to clean
         
     | 
| 
      
 3172 
     | 
    
         
            +
                    return;
         
     | 
| 
      
 3173 
     | 
    
         
            +
                  }
         
     | 
| 
      
 3174 
     | 
    
         
            +
                  let config = pluginHandle.webrtcStuff;
         
     | 
| 
      
 3175 
     | 
    
         
            +
                  if (config) {
         
     | 
| 
      
 3176 
     | 
    
         
            +
                    if (hangupRequest === true) {
         
     | 
| 
      
 3177 
     | 
    
         
            +
                      // Send a hangup request (we don't really care about the response)
         
     | 
| 
      
 3178 
     | 
    
         
            +
                      let request = {
         
     | 
| 
      
 3179 
     | 
    
         
            +
                        "janus": "hangup",
         
     | 
| 
      
 3180 
     | 
    
         
            +
                        "transaction": Janus.randomString(12)
         
     | 
| 
      
 3181 
     | 
    
         
            +
                      };
         
     | 
| 
      
 3182 
     | 
    
         
            +
                      if (pluginHandle.token) request["token"] = pluginHandle.token;
         
     | 
| 
      
 3183 
     | 
    
         
            +
                      if (apisecret) request["apisecret"] = apisecret;
         
     | 
| 
      
 3184 
     | 
    
         
            +
                      Janus.debug("Sending hangup request (handle=" + handleId + "):");
         
     | 
| 
      
 3185 
     | 
    
         
            +
                      Janus.debug(request);
         
     | 
| 
      
 3186 
     | 
    
         
            +
                      if (websockets) {
         
     | 
| 
      
 3187 
     | 
    
         
            +
                        request["session_id"] = sessionId;
         
     | 
| 
      
 3188 
     | 
    
         
            +
                        request["handle_id"] = handleId;
         
     | 
| 
      
 3189 
     | 
    
         
            +
                        ws.send(JSON.stringify(request));
         
     | 
| 
      
 3190 
     | 
    
         
            +
                      } else {
         
     | 
| 
      
 3191 
     | 
    
         
            +
                        Janus.httpAPICall(server + "/" + sessionId + "/" + handleId, {
         
     | 
| 
      
 3192 
     | 
    
         
            +
                          verb: 'POST',
         
     | 
| 
      
 3193 
     | 
    
         
            +
                          withCredentials: withCredentials,
         
     | 
| 
      
 3194 
     | 
    
         
            +
                          body: request
         
     | 
| 
      
 3195 
     | 
    
         
            +
                        });
         
     | 
| 
      
 3196 
     | 
    
         
            +
                      }
         
     | 
| 
      
 3197 
     | 
    
         
            +
                    }
         
     | 
| 
      
 3198 
     | 
    
         
            +
                    // Cleanup stack
         
     | 
| 
      
 3199 
     | 
    
         
            +
                    if (config.volume) {
         
     | 
| 
      
 3200 
     | 
    
         
            +
                      if (config.volume["local"] && config.volume["local"].timer) clearInterval(config.volume["local"].timer);
         
     | 
| 
      
 3201 
     | 
    
         
            +
                      if (config.volume["remote"] && config.volume["remote"].timer) clearInterval(config.volume["remote"].timer);
         
     | 
| 
      
 3202 
     | 
    
         
            +
                    }
         
     | 
| 
      
 3203 
     | 
    
         
            +
                    for (let i in config.bitrate) {
         
     | 
| 
      
 3204 
     | 
    
         
            +
                      if (config.bitrate[i].timer) clearInterval(config.bitrate[i].timer);
         
     | 
| 
      
 3205 
     | 
    
         
            +
                    }
         
     | 
| 
      
 3206 
     | 
    
         
            +
                    config.bitrate = {};
         
     | 
| 
      
 3207 
     | 
    
         
            +
                    if (!config.streamExternal && config.myStream) {
         
     | 
| 
      
 3208 
     | 
    
         
            +
                      Janus.log("Stopping local stream tracks");
         
     | 
| 
      
 3209 
     | 
    
         
            +
                      Janus.stopAllTracks(config.myStream);
         
     | 
| 
      
 3210 
     | 
    
         
            +
                    }
         
     | 
| 
      
 3211 
     | 
    
         
            +
                    config.streamExternal = false;
         
     | 
| 
      
 3212 
     | 
    
         
            +
                    config.myStream = null;
         
     | 
| 
      
 3213 
     | 
    
         
            +
                    // Close PeerConnection
         
     | 
| 
      
 3214 
     | 
    
         
            +
                    try {
         
     | 
| 
      
 3215 
     | 
    
         
            +
                      config.pc.close();
         
     | 
| 
      
 3216 
     | 
    
         
            +
                      // eslint-disable-next-line no-unused-vars
         
     | 
| 
      
 3217 
     | 
    
         
            +
                    } catch (e) {
         
     | 
| 
      
 3218 
     | 
    
         
            +
                      // Do nothing
         
     | 
| 
      
 3219 
     | 
    
         
            +
                    }
         
     | 
| 
      
 3220 
     | 
    
         
            +
                    config.pc = null;
         
     | 
| 
      
 3221 
     | 
    
         
            +
                    config.candidates = null;
         
     | 
| 
      
 3222 
     | 
    
         
            +
                    config.mySdp = null;
         
     | 
| 
      
 3223 
     | 
    
         
            +
                    config.remoteSdp = null;
         
     | 
| 
      
 3224 
     | 
    
         
            +
                    config.iceDone = false;
         
     | 
| 
      
 3225 
     | 
    
         
            +
                    config.dataChannel = {};
         
     | 
| 
      
 3226 
     | 
    
         
            +
                    config.dtmfSender = null;
         
     | 
| 
      
 3227 
     | 
    
         
            +
                    config.insertableStreams = false;
         
     | 
| 
      
 3228 
     | 
    
         
            +
                    config.externalEncryption = false;
         
     | 
| 
      
 3229 
     | 
    
         
            +
                  }
         
     | 
| 
      
 3230 
     | 
    
         
            +
                  pluginHandle.oncleanup();
         
     | 
| 
      
 3231 
     | 
    
         
            +
                }
         
     | 
| 
      
 3232 
     | 
    
         
            +
                function isTrickleEnabled(trickle) {
         
     | 
| 
      
 3233 
     | 
    
         
            +
                  Janus.debug("isTrickleEnabled:", trickle);
         
     | 
| 
      
 3234 
     | 
    
         
            +
                  return trickle === false ? false : true;
         
     | 
| 
      
 3235 
     | 
    
         
            +
                }
         
     | 
| 
      
 3236 
     | 
    
         
            +
              }
         
     | 
| 
      
 3237 
     | 
    
         
            +
              return Janus;
         
     | 
| 
      
 3238 
     | 
    
         
            +
            });
         
     | 
| 
      
 3239 
     | 
    
         
            +
             
     | 
| 
      
 3240 
     | 
    
         
            +
            export { Janus as default };
         
     | 
| 
      
 3241 
     | 
    
         
            +
            //# sourceMappingURL=janus.es.js.map
         
     |