[HTML]播放wav格式音频

[HTML]播放wav格式音频

html 复制代码
<!doctype html>
<html>
  <head>
    <title>音频播放 - 调试版</title>
    <style>
      .error { color: red; }
      .success { color: green; }
      .debug-info { 
        margin-top: 20px;
        border: 1px solid #ccc;
        padding: 10px;
        background-color: #f9f9f9;
      }
    </style>
  </head>
  <body>
    <h1>音频播放 - 调试版</h1>
    
    <div>
      <h3>方法1: 原生Audio元素</h3>
      <button onclick="playAudioNative()">原生播放</button>
      <audio id="audio-native" controls></audio>
    </div>
    
    <div>
      <h3>方法2: Fetch + Blob URL</h3>
      <button onclick="playAudioFetch()">Fetch方式播放</button>
      <audio id="audio-fetch" controls></audio>
    </div>

    <div>
      <h3>方法3: XMLHttpRequest</h3>
      <button onclick="playAudioXHR()">XHR方式播放</button>
      <audio id="audio-xhr" controls></audio>
    </div>

    <div>
      <h3>方法4: iframe嵌入</h3>
      <button onclick="showAudioFrame()">iframe方式</button>
      <div id="frame-container"></div>
    </div>
    
    <div class="debug-info">
      <h3>调试信息:</h3>
      <div id="debug-log"></div>
      
      <h3>检查音频文件:</h3>
      <button onclick="checkAudioFile()">检查文件是否存在</button>
      <div id="file-status"></div>
    </div>
    
    <script>
      const audioUrl = 'http://127.0.0.1:8080/tts-audio/tts_3691e8bf-1ff9-4b81-804e-ae83546279ce.wav';
      
      function log(message, isError = false) {
        const logElem = document.getElementById('debug-log');
        const entry = document.createElement('div');
        entry.textContent = `[${new Date().toLocaleTimeString()}] ${message}`;
        if (isError) entry.className = 'error';
        else entry.className = 'success';
        logElem.appendChild(entry);
        console.log(message);
      }
      
      // 方法1: 原生Audio元素
      function playAudioNative() {
        log('尝试使用原生Audio元素播放...');
        const audio = document.getElementById('audio-native');
        audio.src = audioUrl;
        
        audio.onloadeddata = () => log('音频加载成功,准备播放');
        audio.onplay = () => log('开始播放');
        audio.onplaying = () => log('正在播放');
        audio.onerror = (e) => {
          const errorMsg = getAudioErrorMessage(audio.error);
          log(`音频加载错误: ${errorMsg}`, true);
        };
        
        audio.play().catch(err => {
          log(`播放失败: ${err.message}`, true);
        });
      }
      
      // 方法2: Fetch + Blob URL
      async function playAudioFetch() {
        log('尝试使用Fetch方式获取音频...');
        try {
          const response = await fetch(audioUrl);
          if (!response.ok) {
            log(`服务器响应错误: ${response.status} ${response.statusText}`, true);
            return;
          }
          
          const blob = await response.blob();
          log(`获取音频成功,大小: ${(blob.size / 1024).toFixed(2)}KB`);
          
          const audio = document.getElementById('audio-fetch');
          const url = URL.createObjectURL(blob);
          audio.src = url;
          
          audio.onloadeddata = () => log('Blob音频加载成功');
          audio.onerror = (e) => log(`Blob音频错误: ${getAudioErrorMessage(audio.error)}`, true);
          
          audio.play().catch(err => {
            log(`Blob播放失败: ${err.message}`, true);
          });
        } catch (err) {
          log(`Fetch错误: ${err.message}`, true);
        }
      }
      
      // 方法3: XMLHttpRequest
      function playAudioXHR() {
        log('尝试使用XHR方式获取音频...');
        const xhr = new XMLHttpRequest();
        xhr.open('GET', audioUrl, true);
        xhr.responseType = 'blob';
        
        xhr.onload = function() {
          if (xhr.status === 200) {
            log(`XHR获取音频成功,大小: ${(xhr.response.size / 1024).toFixed(2)}KB`);
            const audio = document.getElementById('audio-xhr');
            const url = URL.createObjectURL(xhr.response);
            audio.src = url;
            
            audio.onloadeddata = () => log('XHR音频加载成功');
            audio.onerror = (e) => log(`XHR音频错误: ${getAudioErrorMessage(audio.error)}`, true);
            
            audio.play().catch(err => {
              log(`XHR播放失败: ${err.message}`, true);
            });
          } else {
            log(`XHR错误: ${xhr.status} ${xhr.statusText}`, true);
          }
        };
        
        xhr.onerror = function() {
          log('XHR网络错误', true);
        };
        
        xhr.send();
      }
      
      // 方法4: iframe嵌入
      function showAudioFrame() {
        log('尝试使用iframe嵌入音频...');
        const container = document.getElementById('frame-container');
        container.innerHTML = `<iframe src="${audioUrl}" width="300" height="100"></iframe>`;
        log('已加载iframe');
      }
      
      // 检查文件是否存在
      async function checkAudioFile() {
        const statusElem = document.getElementById('file-status');
        statusElem.textContent = '正在检查文件...';
        
        try {
          const response = await fetch(audioUrl, { method: 'HEAD' });
          if (response.ok) {
            const contentType = response.headers.get('content-type') || '未知';
            const contentLength = response.headers.get('content-length') || '未知';
            
            statusElem.innerHTML = `
              <div class="success">文件存在!</div>
              <div>Content-Type: ${contentType}</div>
              <div>Content-Length: ${contentLength} 字节</div>
            `;
            
            // 检查CORS头
            const cors = response.headers.get('access-control-allow-origin');
            if (cors) {
              statusElem.innerHTML += `<div>CORS: ${cors}</div>`;
            } else {
              statusElem.innerHTML += `<div class="error">警告: 未检测到CORS头</div>`;
            }
            
          } else {
            statusElem.innerHTML = `<div class="error">文件不存在或无权访问! 状态码: ${response.status}</div>`;
          }
        } catch (err) {
          statusElem.innerHTML = `<div class="error">检查失败: ${err.message}</div>`;
        }
      }
      
      // 获取音频错误信息
      function getAudioErrorMessage(error) {
        if (!error) return '未知错误';
        
        // 媒体错误代码
        switch(error.code) {
          case 1: return 'MEDIA_ERR_ABORTED: 用户中止了获取过程';
          case 2: return 'MEDIA_ERR_NETWORK: 网络错误导致下载失败';
          case 3: return 'MEDIA_ERR_DECODE: 解码失败,可能是文件损坏或浏览器不支持的格式';
          case 4: return 'MEDIA_ERR_SRC_NOT_SUPPORTED: 媒体源不可用或不支持';
          default: return `未知错误(${error.code})`;
        }
      }
      
      // 页面加载时记录浏览器信息
      window.onload = function() {
        log(`浏览器: ${navigator.userAgent}`);
        log('页面已加载,请点击按钮测试不同播放方法');
      };
    </script>
  </body>
</html>
相关推荐
San30.6 小时前
深入理解浏览器渲染流程:从HTML/CSS到像素的奇妙旅程
前端·css·html
IT_陈寒6 小时前
5个Python 3.12新特性让你的代码效率提升50%,第3个太实用了!
前端·人工智能·后端
周杰伦_Jay6 小时前
【Python Web开源框架】Django/Flask/FastAPI/Tornado/Pyramid
前端·python·开源
Tracy9736 小时前
OT83211_VC1:4通道 ASRC OTG(44.1kHz~192kHz)音频采样率转换器产品介绍
嵌入式硬件·音视频·xmos 模组·xmos模组固件
艾小码6 小时前
为什么你的JavaScript代码总是出bug?这5个隐藏陷阱太坑了!
前端·javascript
辻戋8 小时前
从零实现React Scheduler调度器
前端·react.js·前端框架
徐同保8 小时前
使用yarn@4.6.0装包,项目是react+vite搭建的,项目无法启动,报错:
前端·react.js·前端框架
Qrun9 小时前
Windows11安装nvm管理node多版本
前端·vscode·react.js·ajax·npm·html5
中国lanwp9 小时前
全局 npm config 与多环境配置
前端·npm·node.js
JELEE.10 小时前
Django登录注册完整代码(图片、邮箱验证、加密)
前端·javascript·后端·python·django·bootstrap·jquery