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

AudioLevels.js 8.6KB

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