Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

CodecSelection.js 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. import { getLogger } from 'jitsi-meet-logger';
  2. import * as JitsiConferenceEvents from '../../JitsiConferenceEvents';
  3. import CodecMimeType from '../../service/RTC/CodecMimeType';
  4. import * as MediaType from '../../service/RTC/MediaType';
  5. import browser from '../browser';
  6. const logger = getLogger(__filename);
  7. /**
  8. * This class handles the codec selection mechanism for the conference based on the config.js settings.
  9. * The preferred codec is selected based on the settings and the list of codecs supported by the browser.
  10. * The preferred codec is published in presence which is then used by the other endpoints in the
  11. * conference to pick a supported codec at join time and when the call transitions between p2p and jvb
  12. * connections.
  13. */
  14. export class CodecSelection {
  15. /**
  16. * Creates a new instance for a given conference.
  17. *
  18. * @param {JitsiConference} conference the conference instance
  19. * @param {*} options
  20. * @param {string} options.disabledCodec the codec that needs to be disabled.
  21. * @param {boolean} options.enforcePreferredCodec whether codec preference has to be
  22. * enforced even when an endpoints that doesn't support the preferred codec joins the call.
  23. * Falling back to the standard codec will be skipped when this option is true, endpoints
  24. * that do not support the preferred codec may not be able to encode/decode video when this happens.
  25. * @param {string} options.jvbCodec the codec that is preferred on jvb connection.
  26. * @param {string} options.p2pCodec the codec that is preferred on p2p connection.
  27. */
  28. constructor(conference, options) {
  29. this.conference = conference;
  30. this.options = options;
  31. // VP8 cannot be disabled and it will be the default codec when no preference is set.
  32. this.disabledCodec = options.disabledCodec === CodecMimeType.VP8
  33. ? undefined
  34. : this._getCodecMimeType(options.disabledCodec);
  35. // Check if the codec values passed are valid.
  36. const jvbCodec = this._getCodecMimeType(options.jvbCodec);
  37. const p2pCodec = this._getCodecMimeType(options.p2pCodec);
  38. this.jvbPreferredCodec = jvbCodec && this._isCodecSupported(jvbCodec) ? jvbCodec : CodecMimeType.VP8;
  39. this.p2pPreferredCodec = p2pCodec && this._isCodecSupported(p2pCodec) ? p2pCodec : CodecMimeType.VP8;
  40. logger.debug(`Codec preferences for the conference are JVB: ${this.jvbPreferredCodec},
  41. P2P: ${this.p2pPreferredCodec}`);
  42. if (this.jvbPreferredCodec === CodecMimeType.VP9 && !browser.supportsVP9()) {
  43. this.jvbPreferredCodec = CodecMimeType.VP8;
  44. }
  45. this.conference.on(
  46. JitsiConferenceEvents.USER_JOINED,
  47. () => this._selectPreferredCodec());
  48. this.conference.on(
  49. JitsiConferenceEvents.USER_LEFT,
  50. () => this._selectPreferredCodec());
  51. this.conference.on(
  52. JitsiConferenceEvents._MEDIA_SESSION_STARTED,
  53. session => this._onMediaSessionStared(session));
  54. }
  55. /**
  56. * Checks if a given string is a valid video codec mime type.
  57. *
  58. * @param {string} codec the codec string that needs to be validated.
  59. * @returns {CodecMimeType|null} mime type if valid, null otherwise.
  60. * @private
  61. */
  62. _getCodecMimeType(codec) {
  63. if (typeof codec === 'string') {
  64. return Object.values(CodecMimeType).find(value => value === codec.toLowerCase());
  65. }
  66. return null;
  67. }
  68. /**
  69. * Checks if the given codec is supported by the browser.
  70. *
  71. * @param {CodecMimeType} preferredCodec codec to be checked.
  72. * @returns {boolean} true if the given codec is supported, false otherwise.
  73. * @private
  74. */
  75. _isCodecSupported(preferredCodec) {
  76. // Skip the check on FF and RN because they do not support the getCapabilities API.
  77. // It is safe to assume both of them support all the codecs supported by Chrome.
  78. if (browser.isFirefox() || browser.isReactNative()) {
  79. return true;
  80. }
  81. return window.RTCRtpReceiver
  82. && window.RTCRtpReceiver.getCapabilities
  83. && window.RTCRtpReceiver.getCapabilities('video').codecs
  84. .some(codec => codec.mimeType.toLowerCase() === `video/${preferredCodec}`);
  85. }
  86. /**
  87. * Handles the {@link JitsiConferenceEvents._MEDIA_SESSION_STARTED} event. Codecs need to be
  88. * configured on the media session that is newly created.
  89. *
  90. * @param {JingleSessionPC} mediaSession media session that started.
  91. * @returns {void}
  92. * @private
  93. */
  94. _onMediaSessionStared(mediaSession) {
  95. const preferredCodec = mediaSession.isP2P ? this.p2pPreferredCodec : this.jvbPreferredCodec;
  96. const disabledCodec = this.disabledCodec && this._isCodecSupported(this.disabledCodec)
  97. ? this.disabledCodec
  98. : null;
  99. this._selectPreferredCodec(mediaSession, preferredCodec, disabledCodec);
  100. }
  101. /**
  102. * Sets the codec on the media session based on the preferred codec setting and the supported codecs
  103. * published by the remote participants in their presence.
  104. *
  105. * @param {JingleSessionPC} mediaSession session for which the codec selection has to be made.
  106. * @param {CodecMimeType} preferredCodec preferred codec.
  107. * @param {CodecMimeType} disabledCodec codec that needs to be disabled.
  108. */
  109. _selectPreferredCodec(mediaSession = null, preferredCodec = null, disabledCodec = null) {
  110. const session = mediaSession ? mediaSession : this.conference.jvbJingleSession;
  111. const currentCodec = preferredCodec ? preferredCodec : this.jvbPreferredCodec;
  112. let selectedCodec = currentCodec;
  113. if (session && !session.isP2P && !this.options.enforcePreferredCodec) {
  114. const remoteParticipants = this.conference.getParticipants().map(participant => participant.getId());
  115. for (const remote of remoteParticipants) {
  116. const peerMediaInfo = session._signalingLayer.getPeerMediaInfo(remote, MediaType.VIDEO);
  117. const peerCodec = peerMediaInfo?.codecType;
  118. if (peerCodec
  119. && peerCodec !== currentCodec
  120. && (peerCodec !== CodecMimeType.VP9 || browser.supportsVP9())) {
  121. selectedCodec = peerCodec;
  122. }
  123. }
  124. }
  125. session && session.setVideoCodecs(selectedCodec, disabledCodec);
  126. }
  127. /**
  128. * Returns the preferred codec for the conference. The preferred codec for the JVB media session
  129. * is the one that gets published in presence and a comparision is made whenever a participant joins
  130. * or leaves the call.
  131. *
  132. * @returns {CodecMimeType} preferred codec.
  133. */
  134. getPreferredCodec() {
  135. return this.jvbPreferredCodec;
  136. }
  137. }