如何同时启动多个音频标签?

时间:2012-04-30 00:29:17

标签: javascript html5-audio

我有一首曲子要跟我一起演唱,并且能够静音并播放其他歌曲。所以我需要能够同时启动它们。现在,它们都开始有点不同步了:

// Start playing
for ( i = 0; i < 5; i++ ) {
    tracks[i].audio.play();
}

即使这显然也不足以同时启动它们。

javascript中是否有任何方法可以保证HTML5音频标签会同时开始播放?

3 个答案:

答案 0 :(得分:2)

不确定你是否已经这样做了,但这里有一些用于预加载音频的示例代码。

var audios = [];
var loading = 0;
AddNote("2C");
AddNote("2E");
AddNote("2G");
AddNote("3C");

function AddNote(name) {
    loading++;
    var audio = document.createElement("audio");
    audio.loop = true;
    audio.addEventListener("canplaythrough", function () {
        loading--;
        if (loading == 0) // All files are preloaded
            StartPlayingAll();
        }, false);
    audio.src = "piano/" + name + ".mp3";
    audios.push(audio);
}

function StartPlayingAll() {
    for (var i = 0; i < audios.length; i++)
        audios[i].play();
    }
}

您可以尝试的另一件事是在每个曲目上设置audio.currentTime以手动同步音频。

答案 1 :(得分:0)

您可以使用setTimeout在开头短暂延迟后同步它们(您可能希望等待加载所有音频对象)。

JSFiddle:http://jsfiddle.net/bmAYb/35/

var au1 = document.getElementById('au1');
var au2 = document.getElementById('au2');
au1.volume = 1;
au2.volume = 0; //mute
au1.play();
au2.play();
var notfirstRun = false;
//sync for the first time
setTimeout(function() {
    au2.currentTime = au1.currentTime;
    au2.volume = 1;
}, 250);

我最初的想法是使用setInterval每隔x毫秒进行一次同步,但如果volume设置为1(听得见),则会弹出音频。

我的小提琴不完全同步,但它非常接近。您可以100%同步,但您需要将其他音轨上的音频静音或处理弹出。

代码(以及小提琴中的音乐)来自Hungry Media

答案 2 :(得分:0)

我遇到了同样的问题,并找到了使用Audio API的解决方案。

问题在于音频输出具有几毫秒的延迟,因此不可能同时启动多个音频。但是,您可以通过使用ChannelMergerNode将音频源合并为一个来解决此问题。通过在两者之间放置GainNode,您可以分别控制每个音频源的音量。

我为此编写了一个简单的javascript类。这是您可以使用的方式:

var audioMerger = new AudioMerger(["file1.ogg", "file2.mp3", "file3.mp3",
                                   "file4.ogg", "file5.mp3"]);
audioMerger.onBuffered(() => audioMerger.play());

// Make sure it's always in sync (delay should be less than 50 ms)
setInterval(() => {
  if (audioMerger.getDelay() >= 0.05) {
    audioMerger.setTime(audioMerger.getTime());
  }
}, 200);

// Set volume of 3rd audio to 50%
audioMerger.setVolume(0.5, 2);

// When you want to turn it off:
audioMerger.pause();

此代码在PC上的Firefox中将音频之间的延迟减少到不到10毫秒。延迟是如此之小,您不会注意到它。不幸的是,它不适用于Internet Explorer等较旧的浏览器。

这是该类的代码:

class AudioMerger {
  constructor(files) {
    this.files = files;
    this.audios = files.map(file => new Audio(file));

    var AudioContext = window.AudioContext || window.webkitAudioContext;
    var ctx = new AudioContext();
    this.merger = ctx.createChannelMerger(this.audios.length);
    this.merger.connect(ctx.destination);

    this.gains = this.audios.map(audio => {
      var gain = ctx.createGain();
      var source = ctx.createMediaElementSource(audio);
      source.connect(gain);
      gain.connect(this.merger);
      return gain;
    });

    this.buffered = false;

    var load = files.length;
    this.audios.forEach(audio => {
      audio.addEventListener("canplaythrough", () => {
        load--;
        if (load === 0) {
          this.buffered = true;
          if (this.bufferCallback != null) this.bufferCallback();
        }
      });
    });
  }

  onBuffered(callback) {
    if (this.buffered) callback();
    else this.bufferCallback = callback;
  }

  play() {
    this.audios.forEach(audio => audio.play());
  }

  pause() {
    this.audios.forEach(audio => audio.pause());
  }

  getTime() {
    return this.audios[0].currentTime;
  }

  setTime(time) {
    this.audios.forEach(audio => audio.currentTime = time);
  }

  getDelay() {
    var times = [];
    for (var i = 0; i < this.audios.length; i++) {
      times.push(this.audios[i].currentTime);
    }

    var minTime = Math.min.apply(Math, times);
    var maxTime = Math.max.apply(Math, times);
    return maxTime - minTime;
  }

  setVolume(volume, audioID) {
    this.gains[audioID].gain.value = volume;
  }
}