语音聊天监听

 功能实现:

  • 获取用户的音频输入,用于自动检测是否在说话和录音。
  • 检测音频输入的声音变化,以确定是否在说话。
  • 在说话时,开始录音。 当检测到说话停止时,停止录音并发送录音数据。
  • 将录音数据发送到后端进行处理,并根据处理结果更新界面显示。
  • 在界面上实现声音变化的动画效果。

<template>
  <div>
    <h1>音频输入和录音</h1>
    <!-- 录音按钮,根据是否正在录音显示不同文本 -->
    <button @click="toggleRecording">
      {{ isRecording ? '停止录音' : '开始录音' }}
    </button>
    <!-- 当正在录音时显示录音状态和音量条 -->
    <div v-if="isRecording">
      <p>录音中...</p>
      <div
        :style="{
          height: '10px',
          width: '100%',
          backgroundColor: 'blue',
          transform: `scaleX(${volumeLevel})`,
        }"
      ></div>
    </div>
    <!-- 如果有录音完成,显示音频控件 -->
    <audio v-if="audioUrl" controls :src="audioUrl"></audio>
    <div>{{ volumeLevel }}</div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      audioContext: null, // 音频上下文,用于处理音频数据
      mediaRecorder: null, // 媒体录音器,用于录音
      audioChunks: [], // 存储音频数据块
      isRecording: false, // 标记是否正在录音
      audioStream: null, // 音频流
      audioUrl: '', // 录制完成的音频的URL
      volumeLevel: 0, // 音量等级,用于显示音量条
      lastSoundTime: 0, // 记录最后检测到声音的时间
      silenceTimer: null, // 静默检测定时器
      maxVolumeThreshold: 0.01, // 最大声音阈值
    };
  },
  methods: {
    // 切换录音状态
    async toggleRecording() {
      if (!this.isRecording) {
        await this.startRecording();
      } else {
        this.stopRecording();
      }
    },
    // 开始录音
    async startRecording() {
      if (!navigator.mediaDevices) {
        alert('浏览器不支持音频输入设备!');
        return;
      }
      this.audioStream = await navigator.mediaDevices.getUserMedia({
        audio: true,
      });
      this.mediaRecorder = new MediaRecorder(this.audioStream);

      this.audioContext = new AudioContext();

      // 创建音频源
      const source = this.audioContext.createMediaStreamSource(
        this.audioStream
      );

      // 实时音量监控和噪声门控
      const analyser = this.audioContext.createAnalyser();
      source.connect(analyser);
      analyser.fftSize = 2048;
      const bufferLength = analyser.frequencyBinCount;
      const dataArray = new Uint8Array(bufferLength);

      this.mediaRecorder.ondataavailable = (e) => this.audioChunks.push(e.data);
      this.mediaRecorder.onstop = this.handleRecordingStop;
      this.mediaRecorder.start();

      this.isRecording = true;
      // 初始化lastSoundTime为当前时间
      this.lastSoundTime = Date.now(); // 改动点:确保开始记录时间以避免立即停止

      const checkAudio = () => {
        // 读取音频数据,计算当前音量
        analyser.getByteTimeDomainData(dataArray);
        let sum = 0;
        for (let i = 0; i < bufferLength; i++) {
          sum += Math.abs(dataArray[i] - 128); // 计算偏离中心点的绝对值之和
        }
        let currentVolumeLevel = sum / bufferLength / 128; // 计算归一化音量水平
        this.volumeLevel = currentVolumeLevel;

        if (currentVolumeLevel > this.maxVolumeThreshold) {
          // 检测到声音的阈值
          this.lastSoundTime = Date.now(); // 更新最后声音检测时间
          if (this.silenceTimer) {
            clearTimeout(this.silenceTimer); // 如果有声音,则清除现有的定时器
          }
        }

        if (this.isRecording) {
          requestAnimationFrame(checkAudio); // 继续实时检测声音
        }

        // 设置定时器检查是否应该停止录音
        this.silenceTimer = setTimeout(() => {
          if (Date.now() - this.lastSoundTime > 2000) {
            // 如果2秒内无声音
            this.stopRecording(); // 自动停止录音
          }
        }, 2100); // 设置超时时间略长于2秒,以确保时间足够,防止误操作
      };
      checkAudio();
    },

    // 停止录音
    stopRecording() {
      this.mediaRecorder.stop();
      this.audioStream.getTracks().forEach((track) => track.stop());
      this.isRecording = false;
      clearTimeout(this.silenceTimer); // 清除定时器
    },
    // 录音停止后的处理
    handleRecordingStop() {
      const audioBlob = new Blob(this.audioChunks);
      this.audioUrl = URL.createObjectURL(audioBlob);
      this.audioChunks = [];
      this.sendAudioToServer(audioBlob); // 发送音频数据到服务器
    },
    // 将录音发送到服务器
    async sendAudioToServer(audioBlob) {
      console.log('音频数据已发送到服务器');
      return;

      const formData = new FormData();
      formData.append('audio', audioBlob);
      try {
        const response = await fetch('YOUR_BACKEND_URL', {
          method: 'POST',
          body: formData,
        });
        const data = await response.json();
        console.log(data);
      } catch (error) {
        console.error('Error:', error);
      }
    },
  },
};
</script>

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值