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

AudioLevels.js 8.6KB

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