ToB企服应用市场:ToB评测及商务社交产业平台

标题: sourceBuffer failed to execute appendBuffer on sourceBuffer this sourc [打印本页]

作者: 守听    时间: 2024-9-24 11:50
标题: sourceBuffer failed to execute appendBuffer on sourceBuffer this sourc
sourceBuffer failed to execute appendBuffer on sourceBuffer this sourcebuffer is still processing an appendbugger or remove operation, 这个报错
这个错误通常是由于在 SourceBuffer 还在处理前一个 appendBuffer 或 remove 操作时,又尝试执行另一个 appendBuffer 操作。这意味着在 appendBuffer 调用之间没有正确处理并等候前一个操作完成。
要办理这个问题,可以利用一个队列来存储要追加的数据块,并在前一个操作完成后再执行下一个操作。这是通过监听 sourceBuffer 的 updateend 事件来实现的。
以下是一个更详细的示例,确保在一个操作完成后再举行下一个操作:
完备的前端代码示例

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <title>Audio Stream with MediaSource</title>
  6. </head>
  7. <body>
  8.     <audio id="audioElement" controls></audio>
  9.     <script>
  10.         if ('MediaSource' in window) {
  11.             var audio = document.getElementById('audioElement');
  12.             var mediaSource = new MediaSource();
  13.             audio.src = URL.createObjectURL(mediaSource);
  14.             mediaSource.addEventListener('sourceopen', function () {
  15.                 var sourceBuffer = mediaSource.addSourceBuffer('audio/mpeg');
  16.                 // 处理数据块追加的竞争问题
  17.                 let queue = [];
  18.                 let isAppending = false;
  19.                 function appendNextChunk() {
  20.                     if (queue.length > 0 && !isAppending) {
  21.                         isAppending = true;
  22.                         sourceBuffer.appendBuffer(queue.shift());
  23.                     }
  24.                 }
  25.                 sourceBuffer.addEventListener('updateend', function () {
  26.                     isAppending = false;
  27.                     appendNextChunk();
  28.                 });
  29.                 sourceBuffer.addEventListener('error', function (e) {
  30.                     console.error('SourceBuffer error:', e);
  31.                 });
  32.                 fetchAudioData();
  33.             });
  34.             function fetchAudioData() {
  35.                 fetch('/audio') // 替换为你的音频流URL
  36.                     .then(response => response.body.getReader())
  37.                     .then(reader => {
  38.                         function read() {
  39.                             reader.read().then(({ done, value }) => {
  40.                                 if (done) {
  41.                                     mediaSource.endOfStream();
  42.                                     return;
  43.                                 }
  44.                                 queue.push(value);
  45.                                 appendNextChunk();
  46.                                 read();
  47.                             });
  48.                         }
  49.                         read();
  50.                     }).catch(error => {
  51.                         console.error('Fetching audio data failed:', error);
  52.                     });
  53.             }
  54.         } else {
  55.             console.log('The MediaSource API is not supported in this browser.');
  56.         }
  57.     </script>
  58. </body>
  59. </html>
复制代码
后端模拟(Java Servlet)

保持与之前的示例雷同的后端代码,模拟每秒钟返回1KB数据:
  1. import javax.servlet.ServletException;
  2. import javax.servlet.annotation.WebServlet;
  3. import javax.servlet.http.HttpServlet;
  4. import javax.servlet.http.HttpServletRequest;
  5. import javax.servlet.http.HttpServletResponse;
  6. import java.io.IOException;
  7. import java.io.OutputStream;
  8. import java.util.concurrent.TimeUnit;
  9. @WebServlet("/audio")
  10. public class SlowAudioStreamServlet extends HttpServlet {
  11.     private static final int CHUNK_SIZE = 1024; // 1 KB
  12.     private static final int HEADER_SIZE = 128; // 假设头信息大小为128字节
  13.     @Override
  14.     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  15.         resp.setContentType("audio/mpeg");
  16.         OutputStream out = resp.getOutputStream();
  17.         // 构建假头信息
  18.         byte[] v3Header = createFakeV3Header();
  19.         out.write(v3Header);
  20.         out.flush();
  21.         // 模拟每秒返回1KB数据
  22.         try {
  23.             while (true) {
  24.                 byte[] chunk = createFakeAudioData(CHUNK_SIZE);
  25.                 out.write(chunk);
  26.                 out.flush();
  27.                 TimeUnit.SECONDS.sleep(1); // 每秒发送1KB数据
  28.             }
  29.         } catch (InterruptedException e) {
  30.             e.printStackTrace();
  31.         }
  32.     }
  33.     private byte[] createFakeV3Header() {
  34.         byte[] header = new byte[HEADER_SIZE];
  35.         header[0] = 'V';
  36.         header[1] = '3';
  37.         header[2] = 'H';
  38.         header[3] = 'D';
  39.         for (int i = 4; i < HEADER_SIZE; i++) {
  40.             header[i] = 0;
  41.         }
  42.         return header;
  43.     }
  44.     private byte[] createFakeAudioData(int size) {
  45.         byte[] audioData = new byte[size];
  46.         for (int i = 0; i < size; i++) {
  47.             audioData[i] = (byte) ((Math.sin(2 * Math.PI * i / 44100) * 127) + 128); // 生成模拟音频数据
  48.         }
  49.         return audioData;
  50.     }
  51. }
复制代码
解释

如许可以确保 appendBuffer 操作之间不会发生竞争,从而制止 sourceBuffer 错误。

再查抄一下前端代码是否正确,说fetchAudioData 找不到

我查抄并修正了一些可能导致 fetchAudioData 函数找不到的问题,确保代码正确并且函数定义和调用正确。下面是更新后的完备前端代码:
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <title>Audio Stream with MediaSource</title>
  6. </head>
  7. <body>
  8.     <audio id="audioElement" controls></audio>
  9.     <script>
  10.         if ('MediaSource' in window) {
  11.             var audio = document.getElementById('audioElement');
  12.             var mediaSource = new MediaSource();
  13.             audio.src = URL.createObjectURL(mediaSource);
  14.             mediaSource.addEventListener('sourceopen', function () {
  15.                 var sourceBuffer = mediaSource.addSourceBuffer('audio/mpeg');
  16.                 // 处理数据块追加的竞争问题
  17.                 let queue = [];
  18.                 let isAppending = false;
  19.                 function appendNextChunk() {
  20.                     if (queue.length > 0 && !isAppending) {
  21.                         isAppending = true;
  22.                         sourceBuffer.appendBuffer(queue.shift());
  23.                     }
  24.                 }
  25.                 sourceBuffer.addEventListener('updateend', function () {
  26.                     isAppending = false;
  27.                     appendNextChunk();
  28.                 });
  29.                 sourceBuffer.addEventListener('error', function (e) {
  30.                     console.error('SourceBuffer error:', e);
  31.                 });
  32.                 fetchAudioData();
  33.             });
  34.             function fetchAudioData() {
  35.                 fetch('/audio') // 替换为你的音频流URL
  36.                     .then(response => response.body.getReader())
  37.                     .then(reader => {
  38.                         function read() {
  39.                             reader.read().then(({ done, value }) => {
  40.                                 if (done) {
  41.                                     mediaSource.endOfStream();
  42.                                     return;
  43.                                 }
  44.                                 queue.push(value);
  45.                                 appendNextChunk();
  46.                                 read();
  47.                             });
  48.                         }
  49.                         read();
  50.                     }).catch(error => {
  51.                         console.error('Fetching audio data failed:', error);
  52.                     });
  53.             }
  54.         } else {
  55.             console.log('The MediaSource API is not supported in this browser.');
  56.         }
  57.     </script>
  58. </body>
  59. </html>
复制代码
解释

后端模拟(Java Servlet)

保持与之前的示例雷同的后端代码,用于模拟每秒钟返回1KB数据:
  1. import javax.servlet.ServletException;
  2. import javax.servlet.annotation.WebServlet;
  3. import javax.servlet.http.HttpServlet;
  4. import javax.servlet.http.HttpServletRequest;
  5. import javax.servlet.http.HttpServletResponse;
  6. import java.io.IOException;
  7. import java.io.OutputStream;
  8. import java.util.concurrent.TimeUnit;
  9. @WebServlet("/audio")
  10. public class SlowAudioStreamServlet extends HttpServlet {
  11.     private static final int CHUNK_SIZE = 1024; // 1 KB
  12.     private static final int HEADER_SIZE = 128; // 假设头信息大小为128字节
  13.     @Override
  14.     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  15.         resp.setContentType("audio/mpeg");
  16.         OutputStream out = resp.getOutputStream();
  17.         // 构建假头信息
  18.         byte[] v3Header = createFakeV3Header();
  19.         out.write(v3Header);
  20.         out.flush();
  21.         // 模拟每秒返回1KB数据
  22.         try {
  23.             while (true) {
  24.                 byte[] chunk = createFakeAudioData(CHUNK_SIZE);
  25.                 out.write(chunk);
  26.                 out.flush();
  27.                 TimeUnit.SECONDS.sleep(1); // 每秒发送1KB数据
  28.             }
  29.         } catch (InterruptedException e) {
  30.             e.printStackTrace();
  31.         }
  32.     }
  33.     private byte[] createFakeV3Header() {
  34.         byte[] header = new byte[HEADER_SIZE];
  35.         header[0] = 'V';
  36.         header[1] = '3';
  37.         header[2] = 'H';
  38.         header[3] = 'D';
  39.         for (int i = 4; i < HEADER_SIZE; i++) {
  40.             header[i] = 0;
  41.         }
  42.         return header;
  43.     }
  44.     private byte[] createFakeAudioData(int size) {
  45.         byte[] audioData = new byte[size];
  46.         for (int i = 0; i < size; i++) {
  47.             audioData[i] = (byte) ((Math.sin(2 * Math.PI * i / 44100) * 127) + 128); // 生成模拟音频数据
  48.         }
  49.         return audioData;
  50.     }
  51. }
复制代码
请确保后端代码正确部署并运行,以提供所需的音频数据流。这将确保前端代码能够正确获取并处理音频数据,制止 appendBuffer 竞争问题。

Uncaught (in promise) ReferenceError: queue is not defined 报错,前端

对,之前的代码里,queue 和 isAppending 的作用域不正确,导致在某些情况下找不到这些变量。我们须要确保这些变量在得当的作用域内声明。以下是修正后的前端代码:
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <title>Audio Stream with MediaSource</title>
  6. </head>
  7. <body>
  8.     <audio id="audioElement" controls></audio>
  9.     <script>
  10.         if ('MediaSource' in window) {
  11.             var audio = document.getElementById('audioElement');
  12.             var mediaSource = new MediaSource();
  13.             audio.src = URL.createObjectURL(mediaSource);
  14.             mediaSource.addEventListener('sourceopen', function () {
  15.                 var sourceBuffer = mediaSource.addSourceBuffer('audio/mpeg');
  16.                 // 处理数据块追加的竞争问题
  17.                 var queue = [];
  18.                 var isAppending = false;
  19.                 function appendNextChunk() {
  20.                     if (queue.length > 0 && !isAppending) {
  21.                         isAppending = true;
  22.                         sourceBuffer.appendBuffer(queue.shift());
  23.                     }
  24.                 }
  25.                 sourceBuffer.addEventListener('updateend', function () {
  26.                     isAppending = false;
  27.                     appendNextChunk();
  28.                 });
  29.                 sourceBuffer.addEventListener('error', function (e) {
  30.                     console.error('SourceBuffer error:', e);
  31.                 });
  32.                 fetchAudioData(queue, appendNextChunk);
  33.             });
  34.             function fetchAudioData(queue, appendNextChunk) {
  35.                 fetch('/audio') // 替换为你的音频流URL
  36.                     .then(response => response.body.getReader())
  37.                     .then(reader => {
  38.                         function read() {
  39.                             reader.read().then(({ done, value }) => {
  40.                                 if (done) {
  41.                                     mediaSource.endOfStream();
  42.                                     return;
  43.                                 }
  44.                                 queue.push(value);
  45.                                 appendNextChunk();
  46.                                 read();
  47.                             });
  48.                         }
  49.                         read();
  50.                     }).catch(error => {
  51.                         console.error('Fetching audio data failed:', error);
  52.                     });
  53.             }
  54.         } else {
  55.             console.log('The MediaSource API is not supported in this browser.');
  56.         }
  57.     </script>
  58. </body>
  59. </html>
复制代码
解释

这种方式确保了变量的正确引用,并且能够制止 appendBuffer 操作之间的竞争。请确保后端代码正确部署并运行,以提供所需的音频数据流。

哀求完毕后,前端点了播放,没有效果啊,而且哀求的路径返回也是有数据的
为了确保前端代码能够正确处理音频流,并确保音频数据被成功附加到 SourceBuffer,以下是一些步调和改进的前端代码示例,以确保音频数据能够正确播放:
以下是改进的前端代码:
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <title>Audio Stream with MediaSource</title>
  6. </head>
  7. <body>
  8.     <audio id="audioElement" controls></audio>
  9.     <script>
  10.         if ('MediaSource' in window) {
  11.             var audio = document.getElementById('audioElement');
  12.             var mediaSource = new MediaSource();
  13.             audio.src = URL.createObjectURL(mediaSource);
  14.             mediaSource.addEventListener('sourceopen', function () {
  15.                 var sourceBuffer = mediaSource.addSourceBuffer('audio/mpeg');
  16.                 // 处理数据块追加的竞争问题
  17.                 var queue = [];
  18.                 var isAppending = false;
  19.                 function appendNextChunk() {
  20.                     if (queue.length > 0 && !isAppending && !sourceBuffer.updating) {
  21.                         isAppending = true;
  22.                         sourceBuffer.appendBuffer(queue.shift());
  23.                     }
  24.                 }
  25.                 sourceBuffer.addEventListener('updateend', function () {
  26.                     isAppending = false;
  27.                     appendNextChunk();
  28.                 });
  29.                 sourceBuffer.addEventListener('error', function (e) {
  30.                     console.error('SourceBuffer error:', e);
  31.                 });
  32.                 fetchAudioData();
  33.             });
  34.             function fetchAudioData() {
  35.                 fetch('/audio') // 替换为你的音频流URL
  36.                     .then(response => {
  37.                         if (!response.ok) {
  38.                             throw new Error('Network response was not ok');
  39.                         }
  40.                         return response.body.getReader();
  41.                     })
  42.                     .then(reader => {
  43.                         function read() {
  44.                             reader.read().then(({ done, value }) => {
  45.                                 if (done) {
  46.                                     mediaSource.endOfStream();
  47.                                     return;
  48.                                 }
  49.                                 queue.push(value);
  50.                                 appendNextChunk();
  51.                                 read();
  52.                             }).catch(error => {
  53.                                 console.error('Reader read error:', error);
  54.                             });
  55.                         }
  56.                         read();
  57.                     }).catch(error => {
  58.                         console.error('Fetching audio data failed:', error);
  59.                     });
  60.             }
  61.         } else {
  62.             console.log('The MediaSource API is not supported in this browser.');
  63.         }
  64.     </script>
  65. </body>
  66. </html>
复制代码
进一步查抄

后端模拟(Java Servlet)

确保后端代码提供有效的音频流数据。这里是一个简化的示例:
  1. import javax.servlet.ServletException;
  2. import javax.servlet.annotation.WebServlet;
  3. import javax.servlet.http.HttpServlet;
  4. import javax.servlet.http.HttpServletRequest;
  5. import javax.servlet.http.HttpServletResponse;
  6. import java.io.IOException;
  7. import java.io.OutputStream;
  8. import java.util.concurrent.TimeUnit;
  9. @WebServlet("/audio")
  10. public class SlowAudioStreamServlet extends HttpServlet {
  11.     private static final int CHUNK_SIZE = 1024; // 1 KB
  12.     private static final int HEADER_SIZE = 128; // 假设头信息大小为128字节
  13.     @Override
  14.     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  15.         resp.setContentType("audio/mpeg");
  16.         OutputStream out = resp.getOutputStream();
  17.         // 构建假头信息
  18.         byte[] v3Header = createFakeV3Header();
  19.         out.write(v3Header);
  20.         out.flush();
  21.         // 模拟每秒返回1KB数据
  22.         try {
  23.             while (true) {
  24.                 byte[] chunk = createFakeAudioData(CHUNK_SIZE);
  25.                 out.write(chunk);
  26.                 out.flush();
  27.                 TimeUnit.SECONDS.sleep(1); // 每秒发送1KB数据
  28.             }
  29.         } catch (InterruptedException e) {
  30.             e.printStackTrace();
  31.         }
  32.     }
  33.     private byte[] createFakeV3Header() {
  34.         byte[] header = new byte[HEADER_SIZE];
  35.         header[0] = 'V';
  36.         header[1] = '3';
  37.         header[2] = 'H';
  38.         header[3] = 'D';
  39.         for (int i = 4; i < HEADER_SIZE; i++) {
  40.             header[i] = 0;
  41.         }
  42.         return header;
  43.     }
  44.     private byte[] createFakeAudioData(int size) {
  45.         byte[] audioData = new byte[size];
  46.         for (int i = 0; i < size; i++) {
  47.             audioData[i] = (byte) ((Math.sin(2 * Math.PI * i / 44100) * 127) + 128); // 生成模拟音频数据
  48.         }
  49.         return audioData;
  50.     }
  51. }
复制代码
请确保后端返回的数据能够被浏览器正确识别并播放。假如仍然无法播放,请查抄网络哀求的相应头、相应状态以及浏览器控制台中的详细错误信息。

那么我怎样在流轻微到达一定水平哪怕2s ,前端播放器就能播放的效果呢,
为了实现前端播放器在流到达一定水平(例如2秒)后就能开始播放的效果,可以通过以下步调举行优化:
以下是更新的前端代码示例,确保在接收到2秒的音频数据后开始播放:
前端代码

  1. [/code] html
  2. [code]<!DOCTYPE html>
  3. <html lang="en">
  4. <head>
  5.     <meta charset="UTF-8">
  6.     <title>Audio Stream with MediaSource</title>
  7. </head>
  8. <body>
  9.     <audio id="audioElement" controls></audio>
  10.     <script>
  11.         if ('MediaSource' in window) {
  12.             var audio = document.getElementById('audioElement');
  13.             var mediaSource = new MediaSource();
  14.             audio.src = URL.createObjectURL(mediaSource);
  15.             mediaSource.addEventListener('sourceopen', function () {
  16.                 var sourceBuffer = mediaSource.addSourceBuffer('audio/mpeg');
  17.                 // 处理数据块追加的竞争问题
  18.                 var queue = [];
  19.                 var isAppending = false;
  20.                 var totalBufferedDuration = 0; // 总缓冲的时长
  21.                 var requiredBufferDuration = 2; // 需要的缓冲时长(秒)
  22.                 function appendNextChunk() {
  23.                     if (queue.length > 0 && !isAppending && !sourceBuffer.updating) {
  24.                         isAppending = true;
  25.                         sourceBuffer.appendBuffer(queue.shift());
  26.                     }
  27.                 }
  28.                 sourceBuffer.addEventListener('updateend', function () {
  29.                     isAppending = false;
  30.                     totalBufferedDuration = sourceBuffer.buffered.end(0); // 更新总缓冲的时长
  31.                     if (totalBufferedDuration >= requiredBufferDuration && audio.paused) {
  32.                         audio.play(); // 在达到所需缓冲时长后开始播放
  33.                     }
  34.                     appendNextChunk();
  35.                 });
  36.                 sourceBuffer.addEventListener('error', function (e) {
  37.                     console.error('SourceBuffer error:', e);
  38.                 });
  39.                 fetchAudioData();
  40.             });
  41.             function fetchAudioData() {
  42.                 fetch('/audio') // 替换为你的音频流URL
  43.                     .then(response => {
  44.                         if (!response.ok) {
  45.                             throw new Error('Network response was not ok');
  46.                         }
  47.                         return response.body.getReader();
  48.                     })
  49.                     .then(reader => {
  50.                         function read() {
  51.                             reader.read().then(({ done, value }) => {
  52.                                 if (done) {
  53.                                     mediaSource.endOfStream();
  54.                                     return;
  55.                                 }
  56.                                 queue.push(value);
  57.                                 appendNextChunk();
  58.                                 read();
  59.                             }).catch(error => {
  60.                                 console.error('Reader read error:', error);
  61.                             });
  62.                         }
  63.                         read();
  64.                     }).catch(error => {
  65.                         console.error('Fetching audio data failed:', error);
  66.                     });
  67.             }
  68.         } else {
  69.             console.log('The MediaSource API is not supported in this browser.');
  70.         }
  71.     </script>
  72. </body>
  73. </html>
复制代码
解释

后端模拟(Java Servlet)

保持与之前的示例雷同的后端代码,用于模拟每秒钟返回1KB数据:
  1. import javax.servlet.ServletException;
  2. import javax.servlet.annotation.WebServlet;
  3. import javax.servlet.http.HttpServlet;
  4. import javax.servlet.http.HttpServletRequest;
  5. import javax.servlet.http.HttpServletResponse;
  6. import java.io.IOException;
  7. import java.io.OutputStream;
  8. import java.util.concurrent.TimeUnit;
  9. @WebServlet("/audio")
  10. public class SlowAudioStreamServlet extends HttpServlet {
  11.     private static final int CHUNK_SIZE = 1024; // 1 KB
  12.     private static final int HEADER_SIZE = 128; // 假设头信息大小为128字节
  13.     @Override
  14.     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  15.         resp.setContentType("audio/mpeg");
  16.         OutputStream out = resp.getOutputStream();
  17.         // 构建假头信息
  18.         byte[] v3Header = createFakeV3Header();
  19.         out.write(v3Header);
  20.         out.flush();
  21.         // 模拟每秒返回1KB数据
  22.         try {
  23.             while (true) {
  24.                 byte[] chunk = createFakeAudioData(CHUNK_SIZE);
  25.                 out.write(chunk);
  26.                 out.flush();
  27.                 TimeUnit.SECONDS.sleep(1); // 每秒发送1KB数据
  28.             }
  29.         } catch (InterruptedException e) {
  30.             e.printStackTrace();
  31.         }
  32.     }
  33.     private byte[] createFakeV3Header() {
  34.         byte[] header = new byte[HEADER_SIZE];
  35.         header[0] = 'V';
  36.         header[1] = '3';
  37.         header[2] = 'H';
  38.         header[3] = 'D';
  39.         for (int i = 4; i < HEADER_SIZE; i++) {
  40.             header[i] = 0;
  41.         }
  42.         return header;
  43.     }
  44.     private byte[] createFakeAudioData(int size) {
  45.         byte[] audioData = new byte[size];
  46.         for (int i = 0; i < size; i++) {
  47.             audioData[i] = (byte) ((Math.sin(2 * Math.PI * i / 44100) * 127) + 128); // 生成模拟音频数据
  48.         }
  49.         return audioData;
  50.     }
  51. }
复制代码
如许,前端代码会在音频缓冲到达所需的时长(例如2秒)后自动开始播放音频,确保用户体验的平滑性。

你上面的代码 点击播放 没有任何效果,我直接一个audio src标签的时候是确定能播放的

为了确保播放器能够在接收到足够的数据后开始播放,我们须要确保以下几点:
让我们详细调试一下代码,并举行得当的调整,以确保播放器能够正常工作:
前端代码

确保前端代码能够处理缓冲区更新并在足够的数据被缓冲后播放音频:
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <title>Audio Stream with MediaSource</title>
  6. </head>
  7. <body>
  8.     <audio id="audioElement" controls></audio>
  9.     <script>
  10.         if ('MediaSource' in window) {
  11.             var audio = document.getElementById('audioElement');
  12.             var mediaSource = new MediaSource();
  13.             audio.src = URL.createObjectURL(mediaSource);
  14.             mediaSource.addEventListener('sourceopen', function () {
  15.                 var sourceBuffer = mediaSource.addSourceBuffer('audio/mpeg');
  16.                 var queue = [];
  17.                 var isAppending = false;
  18.                 var totalBufferedDuration = 0;
  19.                 var requiredBufferDuration = 2;
  20.                 function appendNextChunk() {
  21.                     if (queue.length > 0 && !isAppending && !sourceBuffer.updating) {
  22.                         isAppending = true;
  23.                         sourceBuffer.appendBuffer(queue.shift());
  24.                     }
  25.                 }
  26.                 sourceBuffer.addEventListener('updateend', function () {
  27.                     isAppending = false;
  28.                     if (sourceBuffer.buffered.length > 0) {
  29.                         totalBufferedDuration = sourceBuffer.buffered.end(0);
  30.                         if (totalBufferedDuration >= requiredBufferDuration && audio.paused) {
  31.                             audio.play();
  32.                         }
  33.                     }
  34.                     appendNextChunk();
  35.                 });
  36.                 sourceBuffer.addEventListener('error', function (e) {
  37.                     console.error('SourceBuffer error:', e);
  38.                 });
  39.                 fetchAudioData();
  40.             });
  41.             function fetchAudioData() {
  42.                 fetch('/audio')
  43.                     .then(response => {
  44.                         if (!response.ok) {
  45.                             throw new Error('Network response was not ok');
  46.                         }
  47.                         return response.body.getReader();
  48.                     })
  49.                     .then(reader => {
  50.                         function read() {
  51.                             reader.read().then(({ done, value }) => {
  52.                                 if (done) {
  53.                                     mediaSource.endOfStream();
  54.                                     return;
  55.                                 }
  56.                                 queue.push(value);
  57.                                 appendNextChunk();
  58.                                 read();
  59.                             }).catch(error => {
  60.                                 console.error('Reader read error:', error);
  61.                             });
  62.                         }
  63.                         read();
  64.                     }).catch(error => {
  65.                         console.error('Fetching audio data failed:', error);
  66.                     });
  67.             }
  68.         } else {
  69.             console.log('The MediaSource API is not supported in this browser.');
  70.         }
  71.     </script>
  72. </body>
  73. </html>
复制代码
  1. 后端代码
复制代码
确保后端正确返回音频数据:
  1. import javax.servlet.ServletException;
  2. import javax.servlet.annotation.WebServlet;
  3. import javax.servlet.http.HttpServlet;
  4. import javax.servlet.http.HttpServletRequest;
  5. import javax.servlet.http.HttpServletResponse;
  6. import java.io.IOException;
  7. import java.io.OutputStream;
  8. import java.util.concurrent.TimeUnit;
  9. @WebServlet("/audio")
  10. public class SlowAudioStreamServlet extends HttpServlet {
  11.     private static final int CHUNK_SIZE = 1024; // 1 KB
  12.     private static final int HEADER_SIZE = 128; // 假设头信息大小为128字节
  13.     @Override
  14.     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  15.         resp.setContentType("audio/mpeg");
  16.         OutputStream out = resp.getOutputStream();
  17.         byte[] v3Header = createFakeV3Header();
  18.         out.write(v3Header);
  19.         out.flush();
  20.         try {
  21.             while (true) {
  22.                 byte[] chunk = createFakeAudioData(CHUNK_SIZE);
  23.                 out.write(chunk);
  24.                 out.flush();
  25.                 TimeUnit.SECONDS.sleep(1); // 每秒发送1KB数据
  26.             }
  27.         } catch (InterruptedException e) {
  28.             e.printStackTrace();
  29.         }
  30.     }
  31.     private byte[] createFakeV3Header() {
  32.         byte[] header = new byte[HEADER_SIZE];
  33.         header[0] = 'V';
  34.         header[1] = '3';
  35.         header[2] = 'H';
  36.         header[3] = 'D';
  37.         for (int i = 4; i < HEADER_SIZE; i++) {
  38.             header[i] = 0;
  39.         }
  40.         return header;
  41.     }
  42.     private byte[] createFakeAudioData(int size) {
  43.         byte[] audioData = new byte[size];
  44.         for (int i = 0; i < size; i++) {
  45.             audioData[i] = (byte) ((Math.sin(2 * Math.PI * i / 44100) * 127) + 128); // 生成模拟音频数据
  46.         }
  47.         return audioData;
  48.     }
  49. }
复制代码
查抄和调试

以上步调应确保播放器在接收到足够的数据后开始播放音频。假如问题仍然存在,请查抄网络哀求和相应的详细信息,并确认数据格式和内容正确。



为了确保利用 MediaSource API 举行流式音频播放,前端代码和后端返回的数据须要正确匹配,并且前端代码须要正确处理缓冲区的填充和播放逻辑。以下是一个更详细的查抄和调试步调,以确保音频流能够正常播放。
前端代码

确保前端代码能够正确处理 MediaSource API 和 SourceBuffer,并能够在缓冲区填充足够数据后开始播放:
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <title>Audio Stream with MediaSource</title>
  6. </head>
  7. <body>
  8.     <audio id="audioElement" controls></audio>
  9.     <script>
  10.         if ('MediaSource' in window) {
  11.             var audio = document.getElementById('audioElement');
  12.             var mediaSource = new MediaSource();
  13.             audio.src = URL.createObjectURL(mediaSource);
  14.             mediaSource.addEventListener('sourceopen', function () {
  15.                 var sourceBuffer = mediaSource.addSourceBuffer('audio/mpeg');
  16.                 var queue = [];
  17.                 var isAppending = false;
  18.                 var totalBufferedDuration = 0;
  19.                 var requiredBufferDuration = 2;
  20.                 function appendNextChunk() {
  21.                     if (queue.length > 0 && !isAppending && !sourceBuffer.updating) {
  22.                         isAppending = true;
  23.                         sourceBuffer.appendBuffer(queue.shift());
  24.                     }
  25.                 }
  26.                 sourceBuffer.addEventListener('updateend', function () {
  27.                     isAppending = false;
  28.                     if (sourceBuffer.buffered.length > 0) {
  29.                         totalBufferedDuration = sourceBuffer.buffered.end(0);
  30.                         if (totalBufferedDuration >= requiredBufferDuration && audio.paused) {
  31.                             audio.play();
  32.                         }
  33.                     }
  34.                     appendNextChunk();
  35.                 });
  36.                 sourceBuffer.addEventListener('error', function (e) {
  37.                     console.error('SourceBuffer error:', e);
  38.                 });
  39.                 fetchAudioData();
  40.             });
  41.             function fetchAudioData() {
  42.                 fetch('http://127.0.0.1:8080/audio/loading')
  43.                     .then(response => {
  44.                         if (!response.ok) {
  45.                             throw new Error('Network response was not ok');
  46.                         }
  47.                         return response.body.getReader();
  48.                     })
  49.                     .then(reader => {
  50.                         function read() {
  51.                             reader.read().then(({ done, value }) => {
  52.                                 if (done) {
  53.                                     mediaSource.endOfStream();
  54.                                     return;
  55.                                 }
  56.                                 queue.push(value);
  57.                                 appendNextChunk();
  58.                                 read();
  59.                             }).catch(error => {
  60.                                 console.error('Reader read error:', error);
  61.                             });
  62.                         }
  63.                         read();
  64.                     }).catch(error => {
  65.                         console.error('Fetching audio data failed:', error);
  66.                     });
  67.             }
  68.         } else {
  69.             console.log('The MediaSource API is not supported in this browser.');
  70.         }
  71.     </script>
  72. </body>
  73. </html>
复制代码
查抄和调试步调

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <title>Audio Stream with MediaSource</title>
  6. </head>
  7. <body>
  8.     <audio id="audioElement" controls></audio>
  9.     <script>
  10.         if ('MediaSource' in window) {
  11.             var audio = document.getElementById('audioElement');
  12.             var mediaSource = new MediaSource();
  13.             audio.src = URL.createObjectURL(mediaSource);
  14.             mediaSource.addEventListener('sourceopen', function () {
  15.                 console.log('MediaSource opened');
  16.                 var sourceBuffer = mediaSource.addSourceBuffer('audio/mpeg');
  17.                 var queue = [];
  18.                 var isAppending = false;
  19.                 var totalBufferedDuration = 0;
  20.                 var requiredBufferDuration = 2;
  21.                 function appendNextChunk() {
  22.                     if (queue.length > 0 && !isAppending && !sourceBuffer.updating) {
  23.                         console.log('Appending next chunk');
  24.                         isAppending = true;
  25.                         sourceBuffer.appendBuffer(queue.shift());
  26.                     }
  27.                 }
  28.                 sourceBuffer.addEventListener('updateend', function () {
  29.                     isAppending = false;
  30.                     console.log('Update ended, total buffered duration:', sourceBuffer.buffered.end(0));
  31.                     if (sourceBuffer.buffered.length > 0) {
  32.                         totalBufferedDuration = sourceBuffer.buffered.end(0);
  33.                         if (totalBufferedDuration >= requiredBufferDuration && audio.paused) {
  34.                             console.log('Starting audio playback');
  35.                             audio.play();
  36.                         }
  37.                     }
  38.                     appendNextChunk();
  39.                 });
  40.                 sourceBuffer.addEventListener('error', function (e) {
  41.                     console.error('SourceBuffer error:', e);
  42.                 });
  43.                 fetchAudioData();
  44.             });
  45.             function fetchAudioData() {
  46.                 fetch('http://127.0.0.1:8080/audio/loading')
  47.                     .then(response => {
  48.                         if (!response.ok) {
  49.                             throw new Error('Network response was not ok');
  50.                         }
  51.                         return response.body.getReader();
  52.                     })
  53.                     .then(reader => {
  54.                         function read() {
  55.                             reader.read().then(({ done, value }) => {
  56.                                 if (done) {
  57.                                     console.log('Stream ended');
  58.                                     mediaSource.endOfStream();
  59.                                     return;
  60.                                 }
  61.                                 queue.push(value);
  62.                                 console.log('Received data chunk, queue length:', queue.length);
  63.                                 appendNextChunk();
  64.                                 read();
  65.                             }).catch(error => {
  66.                                 console.error('Reader read error:', error);
  67.                             });
  68.                         }
  69.                         read();
  70.                     }).catch(error => {
  71.                         console.error('Fetching audio data failed:', error);
  72.                     });
  73.             }
  74.         } else {
  75.             console.log('The MediaSource API is not supported in this browser.');
  76.         }
  77.     </script>
  78. </body>
  79. </html>
复制代码
后端代码

确保后端返回的音频数据能够被前端正确识别息争码:
  1. import javax.servlet.ServletException;
  2. import javax.servlet.annotation.WebServlet;
  3. import javax.servlet.http.HttpServlet;
  4. import javax.servlet.http.HttpServletRequest;
  5. import javax.servlet.http.HttpServletResponse;
  6. import java.io.IOException;
  7. import java.io.OutputStream;
  8. import java.util.concurrent.TimeUnit;
  9. @WebServlet("/audio/loading")
  10. public class SlowAudioStreamServlet extends HttpServlet {
  11.     private static final int CHUNK_SIZE = 1024; // 1 KB
  12.     private static final int HEADER_SIZE = 128; // 假设头信息大小为128字节
  13.     @Override
  14.     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  15.         resp.setContentType("audio/mpeg");
  16.         OutputStream out = resp.getOutputStream();
  17.         byte[] v3Header = createFakeV3Header();
  18.         out.write(v3Header);
  19.         out.flush();
  20.         try {
  21.             while (true) {
  22.                 byte[] chunk = createFakeAudioData(CHUNK_SIZE);
  23.                 out.write(chunk);
  24.                 out.flush();
  25.                 TimeUnit.SECONDS.sleep(1); // 每秒发送1KB数据
  26.             }
  27.         } catch (InterruptedException e) {
  28.             e.printStackTrace();
  29.         }
  30.     }
  31.     private byte[] createFakeV3Header() {
  32.         byte[] header = new byte[HEADER_SIZE];
  33.         header[0] = 'V';
  34.         header[1] = '3';
  35.         header[2] = 'H';
  36.         header[3] = 'D';
  37.         for (int i = 4; i < HEADER_SIZE; i++) {
  38.             header[i] = 0;
  39.         }
  40.         return header;
  41.     }
  42.     private byte[] createFakeAudioData(int size) {
  43.         byte[] audioData = new byte[size];
  44.         for (int i = 0; i < size; i++) {
  45.             audioData[i] = (byte) ((Math.sin(2 * Math.PI * i / 44100) * 127) + 128); // 生成模拟音频数据
  46.         }
  47.         return audioData;
  48.     }
  49. }
复制代码
通过上述步调和代码,你可以逐步排除可能的问题,确保音频流能够正确播放。假如问题仍然存在,请提供浏览器控制台中的详细错误信息,以便进一步调试。

前端 这种方式,不再利用 队列等等的方式,就给我一个简单的方式,直接播放
为了简化前端代码并直接播放音频流,可以移除队列机制,并且直接在数据读取时调用 appendBuffer。以下是一个简化版本的前端代码,它直接读取音频数据并播放:
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <title>Audio Stream with MediaSource</title>
  6. </head>
  7. <body>
  8.     <audio id="audioElement" controls></audio>
  9.     <script>
  10.         if ('MediaSource' in window) {
  11.             const audio = document.getElementById('audioElement');
  12.             const mediaSource = new MediaSource();
  13.             audio.src = URL.createObjectURL(mediaSource);
  14.             mediaSource.addEventListener('sourceopen', () => {
  15.                 const sourceBuffer = mediaSource.addSourceBuffer('audio/mpeg');
  16.                 fetch('http://127.0.0.1:8080/audio/loading')
  17.                     .then(response => {
  18.                         if (!response.ok) {
  19.                             throw new Error('Network response was not ok');
  20.                         }
  21.                         return response.body.getReader();
  22.                     })
  23.                     .then(reader => {
  24.                         function read() {
  25.                             reader.read().then(({ done, value }) => {
  26.                                 if (done) {
  27.                                     mediaSource.endOfStream();
  28.                                     return;
  29.                                 }
  30.                                 sourceBuffer.appendBuffer(value);
  31.                                 read();
  32.                             }).catch(error => {
  33.                                 console.error('Reader read error:', error);
  34.                             });
  35.                         }
  36.                         read();
  37.                     }).catch(error => {
  38.                         console.error('Fetching audio data failed:', error);
  39.                     });
  40.             });
  41.         } else {
  42.             console.log('The MediaSource API is not supported in this browser.');
  43.         }
  44.     </script>
  45. </body>
  46. </html>
复制代码
后端代码

确保后端代码能够以连续的方式发送音频数据:
  1. import javax.servlet.ServletException;
  2. import javax.servlet.annotation.WebServlet;
  3. import javax.servlet.http.HttpServlet;
  4. import javax.servlet.http.HttpServletRequest;
  5. import javax.servlet.http.HttpServletResponse;
  6. import java.io.IOException;
  7. import java.io.OutputStream;
  8. import java.util.concurrent.TimeUnit;
  9. @WebServlet("/audio/loading")
  10. public class SlowAudioStreamServlet extends HttpServlet {
  11.     private static final int CHUNK_SIZE = 1024; // 1 KB
  12.     private static final int HEADER_SIZE = 128; // 假设头信息大小为128字节
  13.     @Override
  14.     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  15.         resp.setContentType("audio/mpeg");
  16.         OutputStream out = resp.getOutputStream();
  17.         byte[] v3Header = createFakeV3Header();
  18.         out.write(v3Header);
  19.         out.flush();
  20.         try {
  21.             while (true) {
  22.                 byte[] chunk = createFakeAudioData(CHUNK_SIZE);
  23.                 out.write(chunk);
  24.                 out.flush();
  25.                 TimeUnit.SECONDS.sleep(1); // 每秒发送1KB数据
  26.             }
  27.         } catch (InterruptedException e) {
  28.             e.printStackTrace();
  29.         }
  30.     }
  31.     private byte[] createFakeV3Header() {
  32.         byte[] header = new byte[HEADER_SIZE];
  33.         header[0] = 'V';
  34.         header[1] = '3';
  35.         header[2] = 'H';
  36.         header[3] = 'D';
  37.         for (int i = 4; i < HEADER_SIZE; i++) {
  38.             header[i] = 0;
  39.         }
  40.         return header;
  41.     }
  42.     private byte[] createFakeAudioData(int size) {
  43.         byte[] audioData = new byte[size];
  44.         for (int i = 0; i < size; i++) {
  45.             audioData[i] = (byte) ((Math.sin(2 * Math.PI * i / 44100) * 127) + 128); // 生成模拟音频数据
  46.         }
  47.         return audioData;
  48.     }
  49. }
复制代码
关键点

通过这种方式,简化了前端逻辑,使音频流能够更加直接地举行播放。

前端照旧播放不了,再简单一些
为了简化实现,我们将移除所有复杂的逻辑,保持前端代码尽可能简单,直接将接收到的音频数据传递给播放器。
前端代码

确保前端代码尽量简单,直接读取和追加数据:
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <title>Audio Stream with MediaSource</title>
  6. </head>
  7. <body>
  8.     <audio id="audioElement" controls></audio>
  9.     <script>
  10.         if ('MediaSource' in window) {
  11.             const audio = document.getElementById('audioElement');
  12.             const mediaSource = new MediaSource();
  13.             audio.src = URL.createObjectURL(mediaSource);
  14.             mediaSource.addEventListener('sourceopen', () => {
  15.                 const sourceBuffer = mediaSource.addSourceBuffer('audio/mpeg');
  16.                 fetch('http://127.0.0.1:8080/audio/loading')
  17.                     .then(response => {
  18.                         if (!response.ok) {
  19.                             throw new Error('Network response was not ok');
  20.                         }
  21.                         return response.body.getReader();
  22.                     })
  23.                     .then(reader => {
  24.                         function read() {
  25.                             reader.read().then(({ done, value }) => {
  26.                                 if (done) {
  27.                                     mediaSource.endOfStream();
  28.                                     return;
  29.                                 }
  30.                                 sourceBuffer.appendBuffer(value);
  31.                                 read();
  32.                             }).catch(error => {
  33.                                 console.error('Reader read error:', error);
  34.                             });
  35.                         }
  36.                         read();
  37.                     }).catch(error => {
  38.                         console.error('Fetching audio data failed:', error);
  39.                     });
  40.             });
  41.             mediaSource.addEventListener('error', function (e) {
  42.                 console.error('MediaSource error:', e);
  43.             });
  44.         } else {
  45.             console.log('The MediaSource API is not supported in this browser.');
  46.         }
  47.     </script>
  48. </body>
  49. </html>
复制代码
后端代码

确保后端以连续的方式发送音频数据:
  1. import javax.servlet.ServletException;
  2. import javax.servlet.annotation.WebServlet;
  3. import javax.servlet.http.HttpServlet;
  4. import javax.servlet.http.HttpServletRequest;
  5. import javax.servlet.http.HttpServletResponse;
  6. import java.io.IOException;
  7. import java.io.OutputStream;
  8. import java.util.concurrent.TimeUnit;
  9. @WebServlet("/audio/loading")
  10. public class SlowAudioStreamServlet extends HttpServlet {
  11.     private static final int CHUNK_SIZE = 1024; // 1 KB
  12.     private static final int HEADER_SIZE = 128; // 假设头信息大小为128字节
  13.     @Override
  14.     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  15.         resp.setContentType("audio/mpeg");
  16.         OutputStream out = resp.getOutputStream();
  17.         byte[] v3Header = createFakeV3Header();
  18.         out.write(v3Header);
  19.         out.flush();
  20.         try {
  21.             while (true) {
  22.                 byte[] chunk = createFakeAudioData(CHUNK_SIZE);
  23.                 out.write(chunk);
  24.                 out.flush();
  25.                 TimeUnit.SECONDS.sleep(1); // 每秒发送1KB数据
  26.             }
  27.         } catch (InterruptedException e) {
  28.             e.printStackTrace();
  29.         }
  30.     }
  31.     private byte[] createFakeV3Header() {
  32.         byte[] header = new byte[HEADER_SIZE];
  33.         header[0] = 'V';
  34.         header[1] = '3';
  35.         header[2] = 'H';
  36.         header[3] = 'D';
  37.         for (int i = 4; i < HEADER_SIZE; i++) {
  38.             header[i] = 0;
  39.         }
  40.         return header;
  41.     }
  42.     private byte[] createFakeAudioData(int size) {
  43.         byte[] audioData = new byte[size];
  44.         for (int i = 0; i < size; i++) {
  45.             audioData[i] = (byte) ((Math.sin(2 * Math.PI * i / 44100) * 127) + 128); // 生成模拟音频数据
  46.         }
  47.         return audioData;
  48.     }
  49. }
复制代码
关键点

通过这种方式,简化前端逻辑,使音频流能够更加直接地举行播放。假如问题仍然存在,请查抄网络哀求、相应的详细信息,并确认数据格式和内容正确。假如须要进一步调试,请查看浏览器控制台中的详细错误信息。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4