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

audio_levels.js 8.6KB

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