您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

AudioLevels.js 8.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. var CanvasUtil = require("./CanvasUtils");
  2. var ASDrawContext = $('#activeSpeakerAudioLevel')[0].getContext('2d');
  3. function initActiveSpeakerAudioLevels() {
  4. var ASRadius = interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE / 2;
  5. var ASCenter = (interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE + ASRadius) / 2;
  6. // Draw a circle.
  7. ASDrawContext.arc(ASCenter, ASCenter, ASRadius, 0, 2 * Math.PI);
  8. // Add a shadow around the circle
  9. ASDrawContext.shadowColor = interfaceConfig.SHADOW_COLOR;
  10. ASDrawContext.shadowOffsetX = 0;
  11. ASDrawContext.shadowOffsetY = 0;
  12. }
  13. /**
  14. * The audio Levels plugin.
  15. */
  16. var AudioLevels = (function(my) {
  17. var audioLevelCanvasCache = {};
  18. my.LOCAL_LEVEL = 'local';
  19. my.init = function () {
  20. initActiveSpeakerAudioLevels();
  21. }
  22. /**
  23. * Updates the audio level canvas for the given peerJid. If the canvas
  24. * didn't exist we create it.
  25. */
  26. my.updateAudioLevelCanvas = function (peerJid, VideoLayout) {
  27. var resourceJid = null;
  28. var videoSpanId = null;
  29. if (!peerJid)
  30. videoSpanId = 'localVideoContainer';
  31. else {
  32. resourceJid = Strophe.getResourceFromJid(peerJid);
  33. videoSpanId = 'participant_' + resourceJid;
  34. }
  35. var videoSpan = document.getElementById(videoSpanId);
  36. if (!videoSpan) {
  37. if (resourceJid)
  38. console.error("No video element for jid", resourceJid);
  39. else
  40. console.error("No video element for local video.");
  41. return;
  42. }
  43. var audioLevelCanvas = $('#' + videoSpanId + '>canvas');
  44. var videoSpaceWidth = $('#remoteVideos').width();
  45. var thumbnailSize = VideoLayout.calculateThumbnailSize(videoSpaceWidth);
  46. var thumbnailWidth = thumbnailSize[0];
  47. var thumbnailHeight = thumbnailSize[1];
  48. if (!audioLevelCanvas || audioLevelCanvas.length === 0) {
  49. audioLevelCanvas = document.createElement('canvas');
  50. audioLevelCanvas.className = "audiolevel";
  51. audioLevelCanvas.style.bottom = "-" + interfaceConfig.CANVAS_EXTRA/2 + "px";
  52. audioLevelCanvas.style.left = "-" + interfaceConfig.CANVAS_EXTRA/2 + "px";
  53. resizeAudioLevelCanvas( audioLevelCanvas,
  54. thumbnailWidth,
  55. thumbnailHeight);
  56. videoSpan.appendChild(audioLevelCanvas);
  57. } else {
  58. audioLevelCanvas = audioLevelCanvas.get(0);
  59. resizeAudioLevelCanvas( audioLevelCanvas,
  60. thumbnailWidth,
  61. thumbnailHeight);
  62. }
  63. };
  64. /**
  65. * Updates the audio level UI for the given resourceJid.
  66. *
  67. * @param resourceJid the resource jid indicating the video element for
  68. * which we draw the audio level
  69. * @param audioLevel the newAudio level to render
  70. */
  71. my.updateAudioLevel = function (resourceJid, audioLevel, largeVideoResourceJid) {
  72. drawAudioLevelCanvas(resourceJid, audioLevel);
  73. var videoSpanId = getVideoSpanId(resourceJid);
  74. var audioLevelCanvas = $('#' + videoSpanId + '>canvas').get(0);
  75. if (!audioLevelCanvas)
  76. return;
  77. var drawContext = audioLevelCanvas.getContext('2d');
  78. var canvasCache = audioLevelCanvasCache[resourceJid];
  79. drawContext.clearRect (0, 0,
  80. audioLevelCanvas.width, audioLevelCanvas.height);
  81. drawContext.drawImage(canvasCache, 0, 0);
  82. if(resourceJid === AudioLevels.LOCAL_LEVEL) {
  83. if(!APP.xmpp.myJid()) {
  84. return;
  85. }
  86. resourceJid = APP.xmpp.myResource();
  87. }
  88. if(resourceJid === largeVideoResourceJid) {
  89. window.requestAnimationFrame(function () {
  90. AudioLevels.updateActiveSpeakerAudioLevel(audioLevel);
  91. });
  92. }
  93. };
  94. my.updateActiveSpeakerAudioLevel = function(audioLevel) {
  95. if($("#activeSpeaker").css("visibility") == "hidden")
  96. return;
  97. ASDrawContext.clearRect(0, 0, 300, 300);
  98. if(audioLevel == 0)
  99. return;
  100. ASDrawContext.shadowBlur = getShadowLevel(audioLevel);
  101. // Fill the shape.
  102. ASDrawContext.fill();
  103. };
  104. /**
  105. * Resizes the given audio level canvas to match the given thumbnail size.
  106. */
  107. function resizeAudioLevelCanvas(audioLevelCanvas,
  108. thumbnailWidth,
  109. thumbnailHeight) {
  110. audioLevelCanvas.width = thumbnailWidth + interfaceConfig.CANVAS_EXTRA;
  111. audioLevelCanvas.height = thumbnailHeight + interfaceConfig.CANVAS_EXTRA;
  112. }
  113. /**
  114. * Draws the audio level canvas into the cached canvas object.
  115. *
  116. * @param resourceJid the resource jid indicating the video element for
  117. * which we draw the audio level
  118. * @param audioLevel the newAudio level to render
  119. */
  120. function drawAudioLevelCanvas(resourceJid, audioLevel) {
  121. if (!audioLevelCanvasCache[resourceJid]) {
  122. var videoSpanId = getVideoSpanId(resourceJid);
  123. var audioLevelCanvasOrig = $('#' + videoSpanId + '>canvas').get(0);
  124. /*
  125. * FIXME Testing has shown that audioLevelCanvasOrig may not exist.
  126. * In such a case, the method CanvasUtil.cloneCanvas may throw an
  127. * error. Since audio levels are frequently updated, the errors have
  128. * been observed to pile into the console, strain the CPU.
  129. */
  130. if (audioLevelCanvasOrig)
  131. {
  132. audioLevelCanvasCache[resourceJid]
  133. = CanvasUtil.cloneCanvas(audioLevelCanvasOrig);
  134. }
  135. }
  136. var canvas = audioLevelCanvasCache[resourceJid];
  137. if (!canvas)
  138. return;
  139. var drawContext = canvas.getContext('2d');
  140. drawContext.clearRect(0, 0, canvas.width, canvas.height);
  141. var shadowLevel = getShadowLevel(audioLevel);
  142. if (shadowLevel > 0)
  143. // drawContext, x, y, w, h, r, shadowColor, shadowLevel
  144. CanvasUtil.drawRoundRectGlow( drawContext,
  145. interfaceConfig.CANVAS_EXTRA/2, interfaceConfig.CANVAS_EXTRA/2,
  146. canvas.width - interfaceConfig.CANVAS_EXTRA,
  147. canvas.height - interfaceConfig.CANVAS_EXTRA,
  148. interfaceConfig.CANVAS_RADIUS,
  149. interfaceConfig.SHADOW_COLOR,
  150. shadowLevel);
  151. }
  152. /**
  153. * Returns the shadow/glow level for the given audio level.
  154. *
  155. * @param audioLevel the audio level from which we determine the shadow
  156. * level
  157. */
  158. function getShadowLevel (audioLevel) {
  159. var shadowLevel = 0;
  160. if (audioLevel <= 0.3) {
  161. shadowLevel = Math.round(interfaceConfig.CANVAS_EXTRA/2*(audioLevel/0.3));
  162. }
  163. else if (audioLevel <= 0.6) {
  164. shadowLevel = Math.round(interfaceConfig.CANVAS_EXTRA/2*((audioLevel - 0.3) / 0.3));
  165. }
  166. else {
  167. shadowLevel = Math.round(interfaceConfig.CANVAS_EXTRA/2*((audioLevel - 0.6) / 0.4));
  168. }
  169. return shadowLevel;
  170. }
  171. /**
  172. * Returns the video span id corresponding to the given resourceJid or local
  173. * user.
  174. */
  175. function getVideoSpanId(resourceJid) {
  176. var videoSpanId = null;
  177. if (resourceJid === AudioLevels.LOCAL_LEVEL
  178. || (APP.xmpp.myResource() && resourceJid
  179. === APP.xmpp.myResource()))
  180. videoSpanId = 'localVideoContainer';
  181. else
  182. videoSpanId = 'participant_' + resourceJid;
  183. return videoSpanId;
  184. }
  185. /**
  186. * Indicates that the remote video has been resized.
  187. */
  188. $(document).bind('remotevideo.resized', function (event, width, height) {
  189. var resized = false;
  190. $('#remoteVideos>span>canvas').each(function() {
  191. var canvas = $(this).get(0);
  192. if (canvas.width !== width + interfaceConfig.CANVAS_EXTRA) {
  193. canvas.width = width + interfaceConfig.CANVAS_EXTRA;
  194. resized = true;
  195. }
  196. if (canvas.heigh !== height + interfaceConfig.CANVAS_EXTRA) {
  197. canvas.height = height + interfaceConfig.CANVAS_EXTRA;
  198. resized = true;
  199. }
  200. });
  201. if (resized)
  202. Object.keys(audioLevelCanvasCache).forEach(function (resourceJid) {
  203. audioLevelCanvasCache[resourceJid].width
  204. = width + interfaceConfig.CANVAS_EXTRA;
  205. audioLevelCanvasCache[resourceJid].height
  206. = height + interfaceConfig.CANVAS_EXTRA;
  207. });
  208. });
  209. return my;
  210. })(AudioLevels || {});
  211. module.exports = AudioLevels;