Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/417.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 使用Web音频API时,播放会在每个块的开头跳过_Javascript_Web Audio Api - Fatal编程技术网

Javascript 使用Web音频API时,播放会在每个块的开头跳过

Javascript 使用Web音频API时,播放会在每个块的开头跳过,javascript,web-audio-api,Javascript,Web Audio Api,我一直在开发一个音乐应用程序,今天我终于开始尝试在其中播放音乐 作为对我的环境设置的概述,我将音乐文件存储为MP3,并使用GridFS上传到MongoDB数据库中。然后,我使用一个socket.io服务器从MongoDB数据库下载块,并将它们作为单独的发射发送到前端,由Web Audio API处理并安排播放 当他们玩的时候,他们的顺序都是正确的,但是每次都有一个很小的小故障或是在同一个地方跳过(大概是在块之间),我似乎无法摆脱。据我所知,它们都排在一起,所以我找不到它们之间有任何间隙或重叠的原

我一直在开发一个音乐应用程序,今天我终于开始尝试在其中播放音乐

作为对我的环境设置的概述,我将音乐文件存储为MP3,并使用GridFS上传到MongoDB数据库中。然后,我使用一个socket.io服务器从MongoDB数据库下载块,并将它们作为单独的发射发送到前端,由Web Audio API处理并安排播放

当他们玩的时候,他们的顺序都是正确的,但是每次都有一个很小的小故障或是在同一个地方跳过(大概是在块之间),我似乎无法摆脱。据我所知,它们都排在一起,所以我找不到它们之间有任何间隙或重叠的原因。任何帮助都将不胜感激。代码如下:

插座布线

socket.on('stream-audio', () => {
  db.client.db("dev").collection('music.files').findOne({"metadata.songId": "3"}).then((result) =>{
      const bucket = new GridFSBucket(db.client.db("dev"), {
        bucketName: "music"
      });
      bucket.openDownloadStream(result._id).on('data',(chunk) => {
      socket.emit('audio-chunk',chunk)
    });
  });
});
前端

//These variable are declared as object variables, hence all of the "this" keywords
context: new (window.AudioContext || window.webkitAudioContext)(),
freeTime: null,
numChunks: 0,
chunkTracker: [],

...

this.socket.on('audio-chunk', (chunk) => {
      //Keeping track of chunk decoding status so that they don't get scheduled out of order
      const chunkId = this.numChunks
      this.chunkTracker.push({
        id: chunkId,
        complete: false,
      });
      this.numChunks += 1;

      //Callback to the decodeAudioData function
      const decodeCallback = (buffer) => {
        var shouldExecute = false;
        const trackIndex = this.chunkTracker.map((e) => e.id).indexOf(chunkId);

        //Checking if either it's the first chunk or the previous chunk has completed
        if(trackIndex !== 0){
          const prevChunk = this.chunkTracker.filter((e) => e.id === (chunkId-1))
          if (prevChunk[0].complete) {
            shouldExecute = true;
          }
        } else {
          shouldExecute = true;
        }

        //THIS IS THE ACTUAL WEB AUDIO API STUFF
        if (shouldExecute) {
          if (this.freeTime === null) {
            this.freeTime = this.context.currentTime
          }
          const source = this.context.createBufferSource();
          source.buffer = buffer
          source.connect(this.context.destination)
          if (this.context.currentTime >= this.freeTime){
            source.start()
            this.freeTime = this.context.currentTime + buffer.duration
          } else {
            source.start(this.freeTime)
            this.freeTime += buffer.duration
          }
          //Update the tracker of the chunks that this one is complete
          this.chunkTracker[trackIndex] = {id: chunkId, complete: true}
        } else {
          //If the previous chunk hasn't processed yet, check again in 50ms
          setTimeout((passBuffer) => {
            decodeCallback(passBuffer)
          },50,buffer);
        }
      }
      decodeCallback.bind(this);
      
      this.context.decodeAudioData(chunk,decodeCallback);
    });
任何帮助都将不胜感激,谢谢

作为对我的环境设置的概述,我将音乐文件存储为MP3,并使用GridFS上传到MongoDB数据库中

如果你愿意,你可以这样做,但是现在我们有了像Minio这样的工具,可以使用更常见的API使这变得更容易

然后,我使用一个socket.io服务器从MongoDB数据库下载数据块,并将它们作为单个发射发送到前端

不要走这条路。没有理由要增加web套接字或Socket.IO的开销。正常的HTTP请求就可以了

其中,网络音频API处理并计划播放

你不能这样流。Web音频API不支持有用的流,除非您碰巧有原始PCM块,而您没有

据我所知,它们都排在一起,所以我找不到它们之间有任何间隙或重叠的原因

有损编解码器不会为您提供精确的样本输出。特别是对于MP3,如果你给它一些任意数量的样本,你将得到至少一个完整的MP3帧(~576个样本)输出。现实情况是,您需要在第一个音频帧之前提供数据,以便它正常工作。如果你想解码一个流,你需要一个流开始。你不能用这种方式独立解码MP3


幸运的是,该解决方案还简化了您的工作。只需从服务器返回HTTP流,并使用HTML音频元素
新音频(url)
。浏览器将处理所有缓冲。只要确保您的服务器处理范围请求,您就可以开始了。

谢谢您提供的所有信息!我昨天才开始学习如何做这一点,所以我知道可能有些事情我需要改变。这回答了我的问题,至少现在是这样,但要明确的是,跳过的原因是有损格式?出于好奇,如果我使用像WAV这样的格式,你认为可以解决这个问题吗?@matthauf从技术上讲,你仍然无法以样本精确的方式安排时间。。。您只能设置一个非常精确的时间戳,并希望它能够取整到您想要的正确样本。如果原始浮点PCM样本的采样率正确,则可以使用ScriptProcessorNode播放它们。当然,您还必须自己处理所有缓冲和其他逻辑。这种方法有一些用例,但你的听起来不像是其中之一。是的,我知道我只是好奇。谢谢你的帮助,我已经实现了你的解决方案,而且它更简单,花费了十分之一的时间。@Matthauf很酷,很高兴你发现它有帮助!另外,欢迎使用堆栈溢出!如果您愿意,您可以单击答案旁边的复选标记,将其标记为“已接受”,这将使未来遇到您的问题的人更容易找到。