Ver Fonte

解决部分版本ios 不能播放的问题

黄琪勇 há 11 meses atrás
pai
commit
030e5dbfcd

+ 98 - 0
src/views/creation/audioVisualDraw.ts

@@ -0,0 +1,98 @@
+    /**
+     * 音频可视化
+     * @param audioDom
+     * @param canvasDom
+     * @param fftSize  2的幂数,最小为32
+     * 注意   由于ios低版本必须在用户操作之后才能初始化 createMediaElementSource 所以必须在用户操作之后初始化
+     */
+    export default function audioVisualDraw(audioDom: HTMLAudioElement, canvasDom: HTMLCanvasElement, fftSize = 128) {
+      type propsType = { canvWidth: number; canvHeight: number; canvFillColor: string; lineColor: string; lineGap: number }
+      // canvas
+      const canvasCtx = canvasDom.getContext("2d")!
+      const { width, height } = canvasDom.getBoundingClientRect()
+      canvasDom.width = width
+      canvasDom.height = height
+      // audio
+      const audioCtx = new AudioContext()
+      const source = audioCtx.createMediaElementSource(audioDom)
+      const analyser = audioCtx.createAnalyser()
+      analyser.fftSize = fftSize
+      source?.connect(analyser)
+      analyser.connect(audioCtx.destination)
+      const dataArray = new Uint8Array(fftSize / 2)
+      const draw = (data: Uint8Array, ctx: CanvasRenderingContext2D, { lineGap, canvWidth, canvHeight, canvFillColor, lineColor }: propsType) => {
+        if (!ctx) return
+        const w = canvWidth
+        const h = canvHeight
+        fillCanvasBackground(ctx, w, h, canvFillColor)
+          // 可视化
+        const dataLen = data.length
+        let step = (w / 2 - lineGap * dataLen) / dataLen
+        step < 1 && (step = 1)
+        const midX = w / 2
+        const midY = h / 2
+        let xLeft = midX
+        for (let i = 0; i < dataLen; i++) {
+          const value = data[i]
+          const percent = value / 255 // 最大值为255
+          const barHeight = percent * midY
+          canvasCtx.fillStyle = lineColor
+          // 中间加间隙
+          if (i === 0) {
+            xLeft -= lineGap / 2
+          }
+          canvasCtx.fillRect(xLeft - step, midY - barHeight, step, barHeight)
+          canvasCtx.fillRect(xLeft - step, midY, step, barHeight)
+          xLeft -= step + lineGap
+        }
+        let xRight = midX
+        for (let i = 0; i < dataLen; i++) {
+          const value = data[i]
+          const percent = value / 255 // 最大值为255
+          const barHeight = percent * midY
+          canvasCtx.fillStyle = lineColor
+          if (i === 0) {
+            xRight += lineGap / 2
+          }
+          canvasCtx.fillRect(xRight, midY - barHeight, step, barHeight)
+          canvasCtx.fillRect(xRight, midY, step, barHeight)
+          xRight += step + lineGap
+        }
+      }
+      const fillCanvasBackground = (ctx: CanvasRenderingContext2D, w: number, h: number, colors: string) => {
+        ctx.clearRect(0, 0, w, h)
+        ctx.fillStyle = colors
+        ctx.fillRect(0, 0, w, h)
+      }
+      const requestAnimationFrameFun = () => {
+        requestAnimationFrame(() => {
+          analyser?.getByteFrequencyData(dataArray)
+          draw(dataArray, canvasCtx, {
+            lineGap: 2,
+            canvWidth: width,
+            canvHeight: height,
+            canvFillColor: "transparent",
+            lineColor: "rgba(255, 255, 255, 0.7)"
+          })
+          if (!isPause) {
+            requestAnimationFrameFun()
+          }
+        })
+      }
+      let isPause = true
+      const playVisualDraw = () => {
+        //audioCtx.resume()  // 重新更新状态   加了暂停和恢复音频音质发生了变化  所以这里取消了
+        isPause = false
+        requestAnimationFrameFun()
+      }
+      const pauseVisualDraw = () => {
+        isPause = true
+        //audioCtx?.suspend()  // 暂停   加了暂停和恢复音频音质发生了变化  所以这里取消了
+        // source?.disconnect()
+        // analyser?.disconnect()
+      }
+      return {
+        playVisualDraw,
+        pauseVisualDraw
+      }
+    }

+ 25 - 121
src/views/creation/index-share.tsx

@@ -49,6 +49,7 @@ import Plyr from "plyr";
 import { Vue3Lottie } from "vue3-lottie";
 import audioBga from "./images/audioBga.json";
 import videobg from "./images/videobg.png";
+import audioVisualDraw from "./audioVisualDraw"
 
 export default defineComponent({
   name: 'creation-detail',
@@ -101,6 +102,7 @@ export default defineComponent({
     })
     const staffDom= ref<HTMLIFrameElement>()
     const {playStaff, pauseStaff, updateProgressStaff} = staffMoveInstance()
+    let isInitAudioVisualDraw =false
     // 点赞
     const onStarChange = async () => {
       await checkLogin();
@@ -171,20 +173,6 @@ export default defineComponent({
         fullscreen: { enabled: false },
       });
       const player = state._plrl
-        // 创建音波数据
-      if(state.playType === "Audio"){
-        const audioDom = document.querySelector("#audioMediaSrc") as HTMLAudioElement
-        const canvasDom = document.querySelector("#audioVisualizer") as HTMLCanvasElement
-        const { pauseVisualDraw, playVisualDraw } = audioVisualDraw(audioDom, canvasDom)
-        player.on('play', () => {
-          lottieDom.value.play()
-          playVisualDraw()
-        });
-        player.on('pause', () => {
-          lottieDom.value.pause()
-          pauseVisualDraw()
-        });
-      }
       // 在微信中运行的时候,微信没有开放自动加载资源的权限,所以要等播放之后才显示播放控制器
       player.on('loadedmetadata', () => {
         plyrState.loaded = true
@@ -221,112 +209,27 @@ export default defineComponent({
     }
     //点击改变播放状态
     function handlerClickPlay(){
-      if (state._plrl.playing) {
-        state._plrl.pause();
-      } else {
-        state._plrl.play();
-      }
-    }
-    /**
-     * 音频可视化
-     * @param audioDom
-     * @param canvasDom
-     * @param fftSize  2的幂数,最小为32
-     */
-    function audioVisualDraw(audioDom: HTMLAudioElement, canvasDom: HTMLCanvasElement, fftSize = 128) {
-      type propsType = { canvWidth: number; canvHeight: number; canvFillColor: string; lineColor: string; lineGap: number }
-      // canvas
-      const canvasCtx = canvasDom.getContext("2d")!
-      const { width, height } = canvasDom.getBoundingClientRect()
-      canvasDom.width = width
-      canvasDom.height = height
-      // audio
-      let audioCtx : AudioContext | null = null
-      let analyser : AnalyserNode | null = null
-      let source : MediaElementAudioSourceNode | null = null
-      const dataArray = new Uint8Array(fftSize / 2)
-      const draw = (data: Uint8Array, ctx: CanvasRenderingContext2D, { lineGap, canvWidth, canvHeight, canvFillColor, lineColor }: propsType) => {
-        if (!ctx) return
-        const w = canvWidth
-        const h = canvHeight
-        fillCanvasBackground(ctx, w, h, canvFillColor)
-          // 可视化
-        const dataLen = data.length
-        let step = (w / 2 - lineGap * dataLen) / dataLen
-        step < 1 && (step = 1)
-        const midX = w / 2
-        const midY = h / 2
-        let xLeft = midX
-        for (let i = 0; i < dataLen; i++) {
-          const value = data[i]
-          const percent = value / 255 // 最大值为255
-          const barHeight = percent * midY
-          canvasCtx.fillStyle = lineColor
-          // 中间加间隙
-          if (i === 0) {
-            xLeft -= lineGap / 2
-          }
-          canvasCtx.fillRect(xLeft - step, midY - barHeight, step, barHeight)
-          canvasCtx.fillRect(xLeft - step, midY, step, barHeight)
-          xLeft -= step + lineGap
-        }
-        let xRight = midX
-        for (let i = 0; i < dataLen; i++) {
-          const value = data[i]
-          const percent = value / 255 // 最大值为255
-          const barHeight = percent * midY
-          canvasCtx.fillStyle = lineColor
-          if (i === 0) {
-            xRight += lineGap / 2
-          }
-          canvasCtx.fillRect(xRight, midY - barHeight, step, barHeight)
-          canvasCtx.fillRect(xRight, midY, step, barHeight)
-          xRight += step + lineGap
-        }
-      }
-      const fillCanvasBackground = (ctx: CanvasRenderingContext2D, w: number, h: number, colors: string) => {
-        ctx.clearRect(0, 0, w, h)
-        ctx.fillStyle = colors
-        ctx.fillRect(0, 0, w, h)
-      }
-      const requestAnimationFrameFun = () => {
-        requestAnimationFrame(() => {
-          analyser?.getByteFrequencyData(dataArray)
-          draw(dataArray, canvasCtx, {
-            lineGap: 2,
-            canvWidth: width,
-            canvHeight: height,
-            canvFillColor: "transparent",
-            lineColor: "rgba(255, 255, 255, 0.7)"
-          })
-          if (!isPause) {
-            requestAnimationFrameFun()
-          }
-        })
-      }
-      let isPause = true
-      const playVisualDraw = () => {
-        if (!audioCtx) {
-          audioCtx = new AudioContext()
-          source = audioCtx.createMediaElementSource(audioDom)
-          analyser = audioCtx.createAnalyser()
-          analyser.fftSize = fftSize
-          source?.connect(analyser)
-          analyser.connect(audioCtx.destination)
-        }
-        //audioCtx.resume()  // 重新更新状态   加了暂停和恢复音频音质发生了变化  所以这里取消了
-        isPause = false
-        requestAnimationFrameFun()
-      }
-      const pauseVisualDraw = () => {
-        isPause = true
-        //audioCtx?.suspend()  // 暂停   加了暂停和恢复音频音质发生了变化  所以这里取消了
-        // source?.disconnect()
-        // analyser?.disconnect()
+      const player = state._plrl;
+      // 由于ios低版本必须在用户操作之后才能初始化 createMediaElementSource 所以必须在用户操作之后初始化
+      if(!isInitAudioVisualDraw && state.playType === "Audio"){
+        isInitAudioVisualDraw = true
+        // 创建音波数据
+        const audioDom = document.querySelector("#audioMediaSrc") as HTMLAudioElement
+        const canvasDom = document.querySelector("#audioVisualizer") as HTMLCanvasElement
+        const { pauseVisualDraw, playVisualDraw } = audioVisualDraw(audioDom, canvasDom)
+        player.on('play', () => {
+          lottieDom.value.play()
+          playVisualDraw()
+        });
+        player.on('pause', () => {
+          lottieDom.value.pause()
+          pauseVisualDraw()
+        });
       }
-      return {
-        playVisualDraw,
-        pauseVisualDraw
+      if (player.playing) {
+        player.pause();
+      } else {
+        player.play();
       }
     }
     function handlerLandscapeScreen(event:any){
@@ -430,8 +333,8 @@ export default defineComponent({
     });
     // 初始化五线谱
     function initStaff(){
-      const src = `${vaildMusicScoreUrl()}/instrument/#/simple-detail?id=${state.musicDetail.musicSheetId}&musicRenderType=${staffState.musicRenderType}&part-index=${staffState.partIndex}`;
-      //const src = `https://dev.kt.colexiu.com/instrument/#/simple-detail?id=${state.musicDetail.musicSheetId}&musicRenderType=${staffState.musicRenderType}&part-index=${staffState.partIndex}`;
+      //const src = `${vaildMusicScoreUrl()}/instrument/#/simple-detail?id=${state.musicDetail.musicSheetId}&musicRenderType=${staffState.musicRenderType}&part-index=${staffState.partIndex}`;
+      const src = `https://dev.kt.colexiu.com/instrument/#/simple-detail?id=${state.musicDetail.musicSheetId}&musicRenderType=${staffState.musicRenderType}&part-index=${staffState.partIndex}`;
       staffState.staffSrc = src
       window.addEventListener('message', (event) => {
         const { api, height } = event.data;
@@ -518,6 +421,7 @@ export default defineComponent({
       state.playType = '';
       state.params.page = 1;
       state.list = [];
+      isInitAudioVisualDraw = false
       if(state._plrl){
         state._plrl.destroy()
       }

+ 30 - 26
src/views/creation/playCreation/index.tsx

@@ -29,6 +29,7 @@ export default defineComponent({
     let _plrl:any
     const playIngShow = ref(true)
     const loaded = ref(false)
+    let isInitAudioVisualDraw = false
     const { registerDrag, unRegisterDrag } = landscapeScreenDrag()
     watch(landscapeScreen, ()=>{
       if(landscapeScreen.value){
@@ -57,20 +58,6 @@ export default defineComponent({
       _plrl.on('loadedmetadata', () => {
         loaded.value = true
       });
-      // 创建音波数据
-      if(playType === "Audio"){
-        const audioDom = document.querySelector("#audioMediaSrc") as HTMLAudioElement
-        const canvasDom = document.querySelector("#audioVisualizer") as HTMLCanvasElement
-        const { pauseVisualDraw, playVisualDraw } = audioVisualDraw(audioDom, canvasDom)
-        _plrl.on('play', () => {
-          lottieDom.value.play()
-          playVisualDraw()
-        });
-        _plrl.on('pause', () => {
-          lottieDom.value.pause()
-          pauseVisualDraw()
-        });
-      }
       _plrl.on('play', () => {
         playIngShow.value = false
         playStaff()
@@ -150,13 +137,22 @@ export default defineComponent({
       type propsType = { canvWidth: number; canvHeight: number; canvFillColor: string; lineColor: string; lineGap: number }
       // canvas
       const canvasCtx = canvasDom.getContext("2d")!
-      const { width, height } = canvasDom.getBoundingClientRect()
+      let { width, height } = canvasDom.getBoundingClientRect()
+      // 这里横屏的时候需要旋转,所以宽高变化一下
+      if(landscapeScreen.value){
+        const _width = width
+        width = height
+        height = _width
+      }
       canvasDom.width = width
       canvasDom.height = height
       // audio
-      let audioCtx : AudioContext | null = null
-      let analyser : AnalyserNode | null = null
-      let source : MediaElementAudioSourceNode | null = null
+      const audioCtx = new AudioContext()
+      const source = audioCtx.createMediaElementSource(audioDom)
+      const analyser = audioCtx.createAnalyser()
+      analyser.fftSize = fftSize
+      source?.connect(analyser)
+      analyser.connect(audioCtx.destination)
       const dataArray = new Uint8Array(fftSize / 2)
       const draw = (data: Uint8Array, ctx: CanvasRenderingContext2D, { lineGap, canvWidth, canvHeight, canvFillColor, lineColor }: propsType) => {
         if (!ctx) return
@@ -219,14 +215,6 @@ export default defineComponent({
       }
       let isPause = true
       const playVisualDraw = () => {
-        if (!audioCtx) {
-          audioCtx = new AudioContext()
-          source = audioCtx.createMediaElementSource(audioDom)
-          analyser = audioCtx.createAnalyser()
-          analyser.fftSize = fftSize
-          source?.connect(analyser)
-          analyser.connect(audioCtx.destination)
-        }
         //audioCtx.resume()  // 重新更新状态   加了暂停和恢复音频音质发生了变化  所以这里取消了
         isPause = false
         requestAnimationFrameFun()
@@ -248,6 +236,22 @@ export default defineComponent({
     }
     //点击改变播放状态
     function handlerClickPlay(event:MouseEvent){
+      //由于ios低版本必须在用户操作之后才能初始化 createMediaElementSource 所以必须在用户操作之后初始化
+      if(!isInitAudioVisualDraw && playType === "Audio"){
+        isInitAudioVisualDraw = true
+        // 创建音波数据
+        const audioDom = document.querySelector("#audioMediaSrc") as HTMLAudioElement
+        const canvasDom = document.querySelector("#audioVisualizer") as HTMLCanvasElement
+        const { pauseVisualDraw, playVisualDraw } = audioVisualDraw(audioDom, canvasDom)
+        _plrl.on('play', () => {
+          lottieDom.value.play()
+          playVisualDraw()
+        });
+        _plrl.on('pause', () => {
+          lottieDom.value.pause()
+          pauseVisualDraw()
+        });
+      }
       // 原生 播放暂停按钮 点击的时候 不触发
       // @ts-ignore
       if(event.target?.matches('button.plyr__control')){