PCMPlayer播放器的使用教程(添加清理暂存区方法)

 解决的问题:在我们使用PCMPlayer播放的时候,时间长,即使停止播放了,也会有一段声音,这是因为音频暂存区没有清理 

解决方案:添加一个stop方法,话不多上 直接上代码  复制就能使用 !!!

function PCMPlayer(option) {
  this.init(option);
}

PCMPlayer.prototype.init = function(option) {
  var defaults = {
      encoding: '16bitInt',
      channels: 1,
      sampleRate: 8000,
      flushingTime: 1000
  };
  this.option = Object.assign({}, defaults, option);
  this.samples = new Float32Array();
  this.flush = this.flush.bind(this);
  this.interval = setInterval(this.flush, this.option.flushingTime);
  this.maxValue = this.getMaxValue();
  this.typedArray = this.getTypedArray();
  this.createContext();
};

PCMPlayer.prototype.getMaxValue = function () {
  var encodings = {
      '8bitInt': 128,
      '16bitInt': 32768,
      '32bitInt': 2147483648,
      '32bitFloat': 1
  };

  return encodings[this.option.encoding] ? encodings[this.option.encoding] : encodings['16bitInt'];
};

PCMPlayer.prototype.getTypedArray = function () {
  var typedArrays = {
      '8bitInt': Int8Array,
      '16bitInt': Int16Array,
      '32bitInt': Int32Array,
      '32bitFloat': Float32Array
  };

  return typedArrays[this.option.encoding] ? typedArrays[this.option.encoding] : typedArrays['16bitInt'];
};

PCMPlayer.prototype.createContext = function() {
  this.audioCtx = new (window.AudioContext || window.webkitAudioContext)();
  this.gainNode = this.audioCtx.createGain();
  this.gainNode.gain.value = 1;
  this.gainNode.connect(this.audioCtx.destination);
  this.startTime = this.audioCtx.currentTime;
};

PCMPlayer.prototype.isTypedArray = function(data) {
  return (data.byteLength && data.buffer && data.buffer.constructor === ArrayBuffer);
};

PCMPlayer.prototype.feed = function(data) {
  if (!this.isTypedArray(data)) return;
  const formattedData = this.getFormatedValue(data);
  var tmp = new Float32Array(this.samples.length + formattedData.length);
  console.log("缓冲区tmp:" + tmp.length);
  tmp.set(this.samples, 0);
  tmp.set(formattedData, this.samples.length);
  this.samples = tmp;
  console.log("缓冲区samples:" + this.samples.length);
};

PCMPlayer.prototype.getFormatedValue = function(inputData) {
  var data = new this.typedArray(inputData.buffer),
      float32 = new Float32Array(data.length),
      i;

  for (i = 0; i < data.length; i++) {
      float32[i] = data[i] / this.maxValue;
  }
  return float32;
};

PCMPlayer.prototype.volume = function(volume) {
  this.gainNode.gain.value = volume;
};

PCMPlayer.prototype.destroy = function() {
  if (this.interval) {
      clearInterval(this.interval);
  }
  this.samples = null;
  this.audioCtx.close();
  this.audioCtx = null;
};

PCMPlayer.prototype.flush = function() {
  if (!this.samples.length) return;
  var bufferSource = this.audioCtx.createBufferSource(),
      length = this.samples.length / this.option.channels,
      audioBuffer = this.audioCtx.createBuffer(this.option.channels, length, this.option.sampleRate),
      audioData,
      channel,
      offset,
      i,
      decrement;

  for (channel = 0; channel < this.option.channels; channel++) {
      audioData = audioBuffer.getChannelData(channel);
      offset = channel;
      decrement = 50;
      for (i = 0; i < length; i++) {
          audioData[i] = this.samples[offset];
          /* fadein */
          if (i < 50) {
              audioData[i] =  (audioData[i] * i) / 50;
          }
          /* fadeout*/
          if (i >= (length - 51)) {
              audioData[i] =  (audioData[i] * decrement--) / 50;
          }
          offset += this.option.channels;
      }
  }
  
  if (this.startTime < this.audioCtx.currentTime) {
      this.startTime = this.audioCtx.currentTime;
  }
  console.log('start vs current ' + this.startTime + ' vs ' + this.audioCtx.currentTime + ' duration: ' + audioBuffer.duration);
  bufferSource.buffer = audioBuffer;
  bufferSource.connect(this.gainNode);
  bufferSource.start(this.startTime);
  this.startTime += audioBuffer.duration;
  this.samples = new Float32Array();
};

PCMPlayer.prototype.stop = function() {
  // 清理所有缓冲区数据
  this.samples = new Float32Array();

  // 检查 AudioContext 状态并确保完全关闭
  if (this.audioCtx && this.audioCtx.state !== 'closed') {
    this.audioCtx.close().then(() => {
      // 确保所有音频缓冲区已停止
      if (this.audioCtx.state === 'closed') {
        setTimeout(() => {
          // 重新创建 AudioContext
          this.audioCtx = new (window.AudioContext || window.webkitAudioContext)();
          this.gainNode = this.audioCtx.createGain();
          this.gainNode.gain.value = 1;
          this.gainNode.connect(this.audioCtx.destination);
          this.startTime = this.audioCtx.currentTime;
        }, 100); // 延迟 100ms 后重新创建 AudioContext
      }
    });
  }
};

export default PCMPlayer;

使用方法:

1 初始化:

var player = new PCMPlayer({
    encoding: '16bitInt',
    channels: 1,
    sampleRate: 16000,
    flushingTime: 1000
});

2 开始播放:

            // 处理音频数据
            const data = new Uint8Array('传入数据源');

            player.feed(data);

3 停止播放,清理暂存区

 player.stop()
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值