From f7ef5ff2f7686e1a4ba3fd9e86ca3ed8e9ea3508 Mon Sep 17 00:00:00 2001 From: Herbert Weng Date: Mon, 12 Jun 2023 15:50:01 +0800 Subject: [PATCH 1/8] update teamsjs sdk to 2.12.0 --- package.json | 2 +- src/index.js | 49 +++++++++++++++++++++++++++++++++------ src/webgl-video-filter.js | 12 +++++----- yarn.lock | 19 +++++---------- 4 files changed, 55 insertions(+), 27 deletions(-) diff --git a/package.json b/package.json index 3c10e35..416e335 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "vite": "^3.0.0" }, "dependencies": { - "@microsoft/teams-js": "^2.2.0", + "@microsoft/teams-js": "^2.12.0", "vite-plugin-mkcert": "^1.9.0" } } diff --git a/src/index.js b/src/index.js index de55fc0..d9cda97 100644 --- a/src/index.js +++ b/src/index.js @@ -26,7 +26,7 @@ function simpleHalfEffect(videoFrame) { for (let i = 1; i < maxLen; i += 4) { //smaple effect just change the value to 100, which effect some pixel value of video frame - videoFrame.data[i + 1] = appliedEffect.pixelValue; + videoFrame.videoFrameBuffer[i + 1] = appliedEffect.pixelValue; } } @@ -34,7 +34,7 @@ let canvas = new OffscreenCanvas(480,360); let videoFilter = new WebglVideoFilter(canvas); videoFilter.init(); //Sample video effect -function videoFrameHandler(videoFrame, notifyVideoProcessed, notifyError) { +function videoBufferHandler(videoFrame, notifyVideoProcessed, notifyError) { switch (selectedEffectId) { case effectIds.half: simpleHalfEffect(videoFrame); @@ -55,6 +55,37 @@ function videoFrameHandler(videoFrame, notifyVideoProcessed, notifyError) { // } } + async function videoStreamHandler(receivedVideoFrame) { + + const originalFrame = receivedVideoFrame.videoFrame; + const buffer = new ArrayBuffer(originalFrame.allocationSize()); + await originalFrame.copyTo(buffer); + const videoFrame = { + width: originalFrame.codedWidth, + height: originalFrame.codedHeight, + videoFrameBuffer: new Uint8ClampedArray(buffer), + } + + let notifyVideoProcessed, notifyError; + + const promise = new Promise((resolve, reject) => { + notifyVideoProcessed = () => { + resolve( + new VideoFrame(videoFrame.videoFrameBuffer, { + codedHeight: videoFrame.height, + codedWidth: videoFrame.width, + format: originalFrame.format, + timestamp: originalFrame.timestamp, + }) + ); + }; + notifyError = reject; + }); + + videoBufferHandler(videoFrame, notifyVideoProcessed, notifyError); + return promise; +} + function clearSelect() { document.getElementById("filter-half").classList.remove("selected"); document.getElementById("filter-gray").classList.remove("selected"); @@ -73,20 +104,24 @@ function effectParameterChanged(effectId) { case effectIds.half: console.log('current effect: half'); document.getElementById("filter-half").classList.add("selected"); - break; + return Promise.resolve(); case effectIds.gray: console.log('current effect: gray'); document.getElementById("filter-gray").classList.add("selected"); - break; + return Promise.resolve(); default: console.log('effect cleared'); - break; + return Promise.resolve(); } } video.registerForVideoEffect(effectParameterChanged); -video.registerForVideoFrame(videoFrameHandler, { - format: "NV12", +video.registerForVideoFrame({ + videoBufferHandler: videoBufferHandler, + videoFrameHandler: videoStreamHandler, + config: { + format: video.VideoFrameFormat.NV12, + } }); // any changes to the UI should notify Teams client. diff --git a/src/webgl-video-filter.js b/src/webgl-video-filter.js index ab58eb3..d987ebd 100644 --- a/src/webgl-video-filter.js +++ b/src/webgl-video-filter.js @@ -41,7 +41,7 @@ 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, - videoFrame.data.subarray(0, uOffset) + videoFrame.videoFrameBuffer.subarray(0, uOffset) ); gl.bindTexture(gl.TEXTURE_2D, this.textureUV); @@ -54,7 +54,7 @@ 0, gl.LUMINANCE_ALPHA, gl.UNSIGNED_BYTE, - videoFrame.data.subarray(uOffset, videoFrame.data.length) + videoFrame.videoFrameBuffer.subarray(uOffset, videoFrame.videoFrameBuffer.length) ); gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); @@ -62,14 +62,14 @@ // Get the YUV data from the effectPixelBuffer for (let i = 0; i < uOffset; i += 1) { - videoFrame.data[i] = this.effectPixelBuffer[4 * i]; + videoFrame.videoFrameBuffer[i] = this.effectPixelBuffer[4 * i]; } let widthIndex = 0; let curIndex = 0; - for (let i = uOffset; i < videoFrame.data.length; i += 2) { - videoFrame.data[i] = this.effectPixelBuffer[ 4 * curIndex + 1]; - videoFrame.data[i + 1] = this.effectPixelBuffer[4 * curIndex + 2]; + for (let i = uOffset; i < videoFrame.videoFrameBuffer.length; i += 2) { + videoFrame.videoFrameBuffer[i] = this.effectPixelBuffer[ 4 * curIndex + 1]; + videoFrame.videoFrameBuffer[i + 1] = this.effectPixelBuffer[4 * curIndex + 2]; widthIndex += 2 curIndex += 2 if (widthIndex > videoFrame.width) { diff --git a/yarn.lock b/yarn.lock index 55f4f39..8f17396 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,12 +7,12 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.14.54.tgz#de2a4be678bd4d0d1ffbb86e6de779cde5999028" integrity sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw== -"@microsoft/teams-js@^2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@microsoft/teams-js/-/teams-js-2.2.0.tgz#1975faf006423bc46efe73de32f1be5e797c19dc" - integrity sha512-nzAunhIK7MZtVRNbamP0LOHZrlKffjOpKy0Qv3iQVfemxBKrWfPRgPrhV1wSmyqOqU8IvJOV2COCt+/sEgQGsQ== +"@microsoft/teams-js@^2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@microsoft/teams-js/-/teams-js-2.12.0.tgz#4fe17da390999b25a7e7f21ec07c29344b726b36" + integrity sha512-4gBtIC/Jc4elZ+R9i1LR+4QFwTAPtJ4P1MsCMDafe3HLtFGu/ZQngG9jZkWQ4A/rP4z1wNaDNn39XC+dLfURHQ== dependencies: - debug "4.3.3" + debug "^4.3.3" "@octokit/auth-token@^3.0.0": version "3.0.1" @@ -127,14 +127,7 @@ before-after-hook@^2.2.0: resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.2.tgz#a6e8ca41028d90ee2c24222f201c90956091613e" integrity sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ== -debug@4.3.3: - version "4.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" - integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== - dependencies: - ms "2.1.2" - -debug@^4.3.4: +debug@^4.3.3, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== From 2235bedb6f52813753a03d86ce2e2e568d1abf2f Mon Sep 17 00:00:00 2001 From: Herbert Weng Date: Wed, 14 Jun 2023 13:13:48 +0800 Subject: [PATCH 2/8] Remove leading white spaces. --- src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index d9cda97..33ceb85 100644 --- a/src/index.js +++ b/src/index.js @@ -55,7 +55,7 @@ function videoBufferHandler(videoFrame, notifyVideoProcessed, notifyError) { // } } - async function videoStreamHandler(receivedVideoFrame) { +async function videoStreamHandler(receivedVideoFrame) { const originalFrame = receivedVideoFrame.videoFrame; const buffer = new ArrayBuffer(originalFrame.allocationSize()); From 3a3727a7a33ac8935651a980d566c220c74986a8 Mon Sep 17 00:00:00 2001 From: Herbert Weng Date: Wed, 5 Jul 2023 13:18:35 +0800 Subject: [PATCH 3/8] gray scale stream handler --- src/index.js | 32 ++------ src/stream-handler-gray.js | 161 +++++++++++++++++++++++++++++++++++++ vite.config.js | 2 +- 3 files changed, 169 insertions(+), 26 deletions(-) create mode 100644 src/stream-handler-gray.js diff --git a/src/index.js b/src/index.js index 33ceb85..7fb4080 100644 --- a/src/index.js +++ b/src/index.js @@ -1,6 +1,7 @@ import { app, video } from "@microsoft/teams-js"; import { WebglVideoFilter } from "./webgl-video-filter"; +import {StreamHandlerGrayFilter } from "./stream-handler-gray"; app.initialize().then(() => { // This is the effect for processing @@ -32,6 +33,7 @@ function simpleHalfEffect(videoFrame) { let canvas = new OffscreenCanvas(480,360); let videoFilter = new WebglVideoFilter(canvas); +let streamHandlerGrayFilter = new StreamHandlerGrayFilter(); videoFilter.init(); //Sample video effect function videoBufferHandler(videoFrame, notifyVideoProcessed, notifyError) { @@ -58,32 +60,12 @@ function videoBufferHandler(videoFrame, notifyVideoProcessed, notifyError) { async function videoStreamHandler(receivedVideoFrame) { const originalFrame = receivedVideoFrame.videoFrame; - const buffer = new ArrayBuffer(originalFrame.allocationSize()); - await originalFrame.copyTo(buffer); - const videoFrame = { - width: originalFrame.codedWidth, - height: originalFrame.codedHeight, - videoFrameBuffer: new Uint8ClampedArray(buffer), + switch (selectedEffectId) { + case effectIds.gray: + return streamHandlerGrayFilter.processVideoFrame(originalFrame); + default: + return Promise.reject('wrong effect id'); } - - let notifyVideoProcessed, notifyError; - - const promise = new Promise((resolve, reject) => { - notifyVideoProcessed = () => { - resolve( - new VideoFrame(videoFrame.videoFrameBuffer, { - codedHeight: videoFrame.height, - codedWidth: videoFrame.width, - format: originalFrame.format, - timestamp: originalFrame.timestamp, - }) - ); - }; - notifyError = reject; - }); - - videoBufferHandler(videoFrame, notifyVideoProcessed, notifyError); - return promise; } function clearSelect() { diff --git a/src/stream-handler-gray.js b/src/stream-handler-gray.js new file mode 100644 index 0000000..55d9714 --- /dev/null +++ b/src/stream-handler-gray.js @@ -0,0 +1,161 @@ +export class StreamHandlerGrayFilter { + constructor() { + this.canvas = document.createElement("canvas"); + // create a WebGL2 context + this.gl = this.canvas.getContext("webgl2"); + + if (!this.gl) { + throw new Error("WebGL2 not supported"); + } + this._setupShaders(); + this._setupBuffers(); + } + + _setupShaders() { + const { gl } = this; + + // create vertex shader + const vertexShaderSource = ` + attribute vec2 a_position; + attribute vec2 a_texCoord; + varying vec2 v_texCoord; + void main() { + gl_Position = vec4(a_position, 0, 1); + v_texCoord = a_texCoord; + } +`; + const vertexShader = gl.createShader(gl.VERTEX_SHADER); + if (!vertexShader) { + throw new Error("Failed to create vertex shader"); + } + gl.shaderSource(vertexShader, vertexShaderSource); + gl.compileShader(vertexShader); + + // create fragment shader + const fragmentShaderSource = ` + precision mediump float; + uniform sampler2D u_texture; + varying vec2 v_texCoord; + void main() { + vec4 color = texture2D(u_texture, v_texCoord); + float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114)); + gl_FragColor = vec4(vec3(gray), color.a); + } +`; + const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); + if (!fragmentShader) { + throw new Error("Failed to create fragment shader"); + } + gl.shaderSource(fragmentShader, fragmentShaderSource); + gl.compileShader(fragmentShader); + + // create program + const program = gl.createProgram(); + if (!program) { + throw new Error("Failed to create program"); + } + gl.attachShader(program, vertexShader); + gl.attachShader(program, fragmentShader); + gl.linkProgram(program); + + if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { + throw new Error( + `Unable to initialize the shader program: ${gl.getProgramInfoLog( + program + )}` + ); + } + gl.useProgram(program); + this.program = program; + } + + _setupBuffers() { + const { gl, program } = this; + + if (!program) { + throw new Error("Program not initialized"); + } + // create buffer + const positionBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); + gl.bufferData( + gl.ARRAY_BUFFER, + new Float32Array([-1, -1, -1, 1, 1, -1, 1, 1]), + gl.STATIC_DRAW + ); + + // create attributes + const positionAttributeLocation = gl.getAttribLocation( + program, + "a_position" + ); + gl.enableVertexAttribArray(positionAttributeLocation); + gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0); + + const texCoordBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer); + gl.bufferData( + gl.ARRAY_BUFFER, + new Float32Array([0, 0, 0, 1, 1, 0, 1, 1]), + gl.STATIC_DRAW + ); + + const texCoordAttributeLocation = gl.getAttribLocation( + program, + "a_texCoord" + ); + gl.enableVertexAttribArray(texCoordAttributeLocation); + gl.vertexAttribPointer(texCoordAttributeLocation, 2, gl.FLOAT, false, 0, 0); + } + + async processVideoFrame(videoFrame) { + try { + const { gl, program } = this; + + if (!program) { + throw new Error("Program not initialized"); + } + + const imageBitmap = await createImageBitmap(videoFrame, {imageOrientation: "flipY"}/* We need this otherwise the frame is rendered upside down */); + + this.canvas.width = imageBitmap.width; + this.canvas.height = imageBitmap.height; + this.gl.viewport(0, 0, imageBitmap.width, imageBitmap.height); + const texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.texImage2D( + gl.TEXTURE_2D, + 0, + gl.RGBA, + imageBitmap.width, + imageBitmap.height, + 0, + gl.RGBA, + gl.UNSIGNED_BYTE, + imageBitmap + ); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + // set uniforms + const textureUniformLocation = gl.getUniformLocation( + program, + "u_texture" + ); + gl.uniform1i(textureUniformLocation, 0); + + // draw + gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); + + return new VideoFrame(this.canvas, { + timestamp: videoFrame.timestamp, + displayHeight: videoFrame.displayHeight, + displayWidth: videoFrame.displayWidth, + }); + } catch (e) { + console.error(e); + Promise.reject(e); + } + } +} diff --git a/vite.config.js b/vite.config.js index 78238a0..5223730 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,6 +1,6 @@ import mkcert from 'vite-plugin-mkcert' export default { - base: '/teams-videoapp-sample/app/', + base: '/teams-videoapp-sample/', build: { outDir: './dist/app' }, From 3800a9c97f1eacf7b0d17c90d57d23f31145ef0b Mon Sep 17 00:00:00 2001 From: Herbert Weng Date: Wed, 5 Jul 2023 13:45:28 +0800 Subject: [PATCH 4/8] half effect stream handler --- src/index.js | 6 +++++- src/stream-handler-half.js | 23 +++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 src/stream-handler-half.js diff --git a/src/index.js b/src/index.js index 7fb4080..3ab592d 100644 --- a/src/index.js +++ b/src/index.js @@ -2,6 +2,7 @@ import { app, video } from "@microsoft/teams-js"; import { WebglVideoFilter } from "./webgl-video-filter"; import {StreamHandlerGrayFilter } from "./stream-handler-gray"; +import {StreamHandlerHalfFilter } from "./stream-handler-half"; app.initialize().then(() => { // This is the effect for processing @@ -33,8 +34,9 @@ function simpleHalfEffect(videoFrame) { let canvas = new OffscreenCanvas(480,360); let videoFilter = new WebglVideoFilter(canvas); -let streamHandlerGrayFilter = new StreamHandlerGrayFilter(); videoFilter.init(); +let streamHandlerGrayFilter = new StreamHandlerGrayFilter(); +let streamHandlerHalfFilter = new StreamHandlerHalfFilter(simpleHalfEffect); //Sample video effect function videoBufferHandler(videoFrame, notifyVideoProcessed, notifyError) { switch (selectedEffectId) { @@ -63,6 +65,8 @@ async function videoStreamHandler(receivedVideoFrame) { switch (selectedEffectId) { case effectIds.gray: return streamHandlerGrayFilter.processVideoFrame(originalFrame); + case effectIds.half: + return streamHandlerHalfFilter.processVideoFrame(originalFrame); default: return Promise.reject('wrong effect id'); } diff --git a/src/stream-handler-half.js b/src/stream-handler-half.js new file mode 100644 index 0000000..0e04ee3 --- /dev/null +++ b/src/stream-handler-half.js @@ -0,0 +1,23 @@ +export class StreamHandlerHalfFilter { + constructor(simpleHalfEffect) { + this.simpleHalfEffect = simpleHalfEffect; + } + + async processVideoFrame(originalFrame) { + const buffer = new ArrayBuffer(originalFrame.allocationSize()); + // get video buffer from VideoFrame + await originalFrame.copyTo(buffer); + const videoFrame = { + width: originalFrame.codedWidth, + height: originalFrame.codedHeight, + videoFrameBuffer: new Uint8ClampedArray(buffer), + }; + this.simpleHalfEffect(videoFrame); + return new VideoFrame(videoFrame.videoFrameBuffer, { + codedHeight: videoFrame.height, + codedWidth: videoFrame.width, + format: originalFrame.format, + timestamp: originalFrame.timestamp, + }); + } +} From f56b1fb084858ce7b54865199be4324aaaab0431 Mon Sep 17 00:00:00 2001 From: Herbert Weng Date: Wed, 5 Jul 2023 13:49:38 +0800 Subject: [PATCH 5/8] clean code --- src/index.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/index.js b/src/index.js index 3ab592d..77efc76 100644 --- a/src/index.js +++ b/src/index.js @@ -16,11 +16,9 @@ let effectIds = { gray: "b0c8896c-7be8-4645-ae02-a8bc9b0355e5", } -// This is the effect linked with UI -let uiSelectedEffect = {}; let selectedEffectId = undefined; -let errorOccurs = false; -let useSimpleEffect = false; + +//Sample video effect function simpleHalfEffect(videoFrame) { const maxLen = (videoFrame.height * videoFrame.width) / @@ -37,7 +35,7 @@ let videoFilter = new WebglVideoFilter(canvas); videoFilter.init(); let streamHandlerGrayFilter = new StreamHandlerGrayFilter(); let streamHandlerHalfFilter = new StreamHandlerHalfFilter(simpleHalfEffect); -//Sample video effect + function videoBufferHandler(videoFrame, notifyVideoProcessed, notifyError) { switch (selectedEffectId) { case effectIds.half: From 3d45be87b5627b493f7652b0c913db36abc82088 Mon Sep 17 00:00:00 2001 From: Herbert Weng Date: Fri, 7 Jul 2023 14:21:21 +0800 Subject: [PATCH 6/8] don't change vite config --- vite.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vite.config.js b/vite.config.js index 5223730..78238a0 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,6 +1,6 @@ import mkcert from 'vite-plugin-mkcert' export default { - base: '/teams-videoapp-sample/', + base: '/teams-videoapp-sample/app/', build: { outDir: './dist/app' }, From 98abfe67add3cb49bf3f97048a7860ca893e1ffb Mon Sep 17 00:00:00 2001 From: Herbert Weng Date: Tue, 8 Aug 2023 18:00:32 +0800 Subject: [PATCH 7/8] don't use bitmap and don't create texture on every frame --- src/stream-handler-gray.js | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/stream-handler-gray.js b/src/stream-handler-gray.js index 55d9714..641652f 100644 --- a/src/stream-handler-gray.js +++ b/src/stream-handler-gray.js @@ -7,8 +7,10 @@ export class StreamHandlerGrayFilter { if (!this.gl) { throw new Error("WebGL2 not supported"); } + this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, true); this._setupShaders(); this._setupBuffers(); + this._bindTexture(); } _setupShaders() { @@ -108,6 +110,11 @@ export class StreamHandlerGrayFilter { gl.vertexAttribPointer(texCoordAttributeLocation, 2, gl.FLOAT, false, 0, 0); } + _bindTexture() { + const {gl} = this; + gl.bindTexture(gl.TEXTURE_2D, gl.createTexture()); + } + async processVideoFrame(videoFrame) { try { const { gl, program } = this; @@ -116,23 +123,19 @@ export class StreamHandlerGrayFilter { throw new Error("Program not initialized"); } - const imageBitmap = await createImageBitmap(videoFrame, {imageOrientation: "flipY"}/* We need this otherwise the frame is rendered upside down */); - - this.canvas.width = imageBitmap.width; - this.canvas.height = imageBitmap.height; - this.gl.viewport(0, 0, imageBitmap.width, imageBitmap.height); - const texture = gl.createTexture(); - gl.bindTexture(gl.TEXTURE_2D, texture); + this.canvas.width = videoFrame.codedWidth; + this.canvas.height = videoFrame.codedHeight; + this.gl.viewport(0, 0, videoFrame.codedWidth, videoFrame.codedHeight); gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, - imageBitmap.width, - imageBitmap.height, + videoFrame.codedWidth, + videoFrame.codedHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, - imageBitmap + videoFrame ); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); From 9c14022903f4ec517b5c3adfe6f7afb6f345e246 Mon Sep 17 00:00:00 2001 From: Herbert Weng Date: Tue, 8 Aug 2023 18:00:51 +0800 Subject: [PATCH 8/8] udpate to use js sdk 2.14.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 416e335..3fb3f78 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "vite": "^3.0.0" }, "dependencies": { - "@microsoft/teams-js": "^2.12.0", + "@microsoft/teams-js": "^2.14.0", "vite-plugin-mkcert": "^1.9.0" } } diff --git a/yarn.lock b/yarn.lock index 8f17396..f52649d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,10 +7,10 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.14.54.tgz#de2a4be678bd4d0d1ffbb86e6de779cde5999028" integrity sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw== -"@microsoft/teams-js@^2.12.0": - version "2.12.0" - resolved "https://registry.yarnpkg.com/@microsoft/teams-js/-/teams-js-2.12.0.tgz#4fe17da390999b25a7e7f21ec07c29344b726b36" - integrity sha512-4gBtIC/Jc4elZ+R9i1LR+4QFwTAPtJ4P1MsCMDafe3HLtFGu/ZQngG9jZkWQ4A/rP4z1wNaDNn39XC+dLfURHQ== +"@microsoft/teams-js@^2.14.0": + version "2.14.0" + resolved "https://registry.yarnpkg.com/@microsoft/teams-js/-/teams-js-2.14.0.tgz#4009fe936e8c230336c6484277a6410131747bb4" + integrity sha512-1KzAPLI6N5HxR8QuFEktGbqCWKzpHJoLhMNHkiY8/9bNJAEwXyBiB4Q+5WUE14LT7JELhdQAy/fw9Y26lJ/5Bw== dependencies: debug "^4.3.3"