音频系统分析.md 8.47 KB

音频系统分析

最后更新: 2026-02-09 相关文件:

  • src/components/audioBackground.vue - 背景音频(单模式)
  • src/components/audioBackground1.vue - 背景音频(备用)
  • src/components/audioList.vue - 音频列表(播放列表模式)
  • src/api/map.js - 音频 API (mapAudioAPI)

系统架构

双模式设计

音频系统支持两种播放模式:

  1. 单模式 (Single Mode)

    • 组件: audioBackground.vue, audioBackground1.vue
    • 用途: 单个音频的背景播放
    • 特点: 简单、轻量
  2. 播放列表模式 (Playlist Mode)

    • 组件: audioList.vue
    • 用途: 多个音频的顺序播放
    • 特点: 支持播放列表控制

状态管理

Pinia Store (src/store/index.js):

// 单模式状态
audio_entity: null,        // 当前音频实体
audio_status: false,       // 播放状态

// 播放列表模式状态
audio_list_entity: [],     // 播放列表
audio_list_status: false,  // 播放状态

核心功能

1. 音频加载

API 端点: /srv/?a=map_audio

// src/api/map.js
export const mapAudioAPI = (params) => fn(fetch.get(Api.MAP_AUDIO, params));

请求参数:

  • id: 位置/景点 ID
  • type: 音频类型(可选)

响应数据:

{
  code: 1,
  data: {
    audioUrl: '/audio/guide.mp3',
    title: '景点介绍',
    duration: 120,
    // 其他音频信息
  },
  msg: ''
}

2. 单模式播放

组件: audioBackground.vue

功能:

  • ✅ 播放/暂停控制
  • ✅ 进度条显示
  • ✅ 音量控制
  • ✅ 自动播放(可选)
  • ✅ 循环播放(可选)

使用示例:

<template>
  <audioBackground
    :audio-url="currentAudio"
    :autoplay="true"
    @play="handlePlay"
    @pause="handlePause"
    @ended="handleEnded"
  />
</template>

<script setup>
import audioBackground from '@components/audioBackground.vue';
import { ref } from 'vue';

const currentAudio = ref('/audio/guide.mp3');

const handlePlay = () => {
  console.log('开始播放');
};

const handlePause = () => {
  console.log('暂停播放');
};

const handleEnded = () => {
  console.log('播放结束');
};
</script>

3. 播放列表模式

组件: audioList.vue

功能:

  • ✅ 播放列表管理
  • ✅ 上一首/下一首
  • ✅ 播放进度
  • ✅ 当前播放高亮
  • ✅ 自动播放下一首
  • ✅ 列表循环

使用示例:

<template>
  <audioList
    v-model:playlist="audioPlaylist"
    :current-index="currentIndex"
    @play="handlePlay"
    @pause="handlePause"
    @next="handleNext"
    @prev="handlePrev"
  />
</template>

<script setup>
import audioList from '@components/audioList.vue';
import { ref } from 'vue';

const audioPlaylist = ref([
  {
    id: 1,
    title: '景点介绍 1',
    url: '/audio/guide1.mp3',
    duration: 120
  },
  {
    id: 2,
    title: '景点介绍 2',
    url: '/audio/guide2.mp3',
    duration: 90
  }
]);

const currentIndex = ref(0);

const handlePlay = (index) => {
  console.log('播放索引:', index);
};

const handleNext = () => {
  if (currentIndex.value < audioPlaylist.value.length - 1) {
    currentIndex.value++;
  }
};

const handlePrev = () => {
  if (currentIndex.value > 0) {
    currentIndex.value--;
  }
};
</script>

4. 音频状态同步

Pinia Store:

import { defineStore } from 'pinia';

export const useAudioStore = defineStore('audio', {
  state: () => ({
    // 单模式
    audio_entity: null,
    audio_status: false,

    // 播放列表模式
    audio_list_entity: [],
    audio_list_status: false,
    audio_list_index: 0,
  }),

  actions: {
    // 设置单模式音频
    setAudio(entity) {
      this.audio_entity = entity;
    },

    // 播放/暂停单模式
    toggleAudio() {
      this.audio_status = !this.audio_status;
    },

    // 设置播放列表
    setPlaylist(list) {
      this.audio_list_entity = list;
    },

    // 播放/暂停播放列表
    togglePlaylist() {
      this.audio_list_status = !this.audio_list_status;
    },

    // 下一首
    nextTrack() {
      if (this.audio_list_index < this.audio_list_entity.length - 1) {
        this.audio_list_index++;
      }
    },

    // 上一首
    prevTrack() {
      if (this.audio_list_index > 0) {
        this.audio_list_index--;
      }
    },
  },
});

音频格式

支持的格式

  • ✅ MP3(推荐)
  • ✅ WAV
  • ✅ OGG
  • ✅ AAC
  • ✅ M4A

推荐配置

编码格式: MP3 比特率: 128 kbps 采样率: 44.1 kHz 声道: 立体声

文件大小建议

音频时长 推荐大小
< 1 分钟 < 1 MB
1-3 分钟 1-3 MB
3-5 分钟 3-5 MB
> 5 分钟 建议分割

性能优化

1. 懒加载

// 仅在需要时加载音频
const loadAudio = async (url) => {
  const audio = new Audio();
  audio.src = url;
  await audio.load(); // 预加载
  return audio;
};

2. 缓存策略

// 缓存已加载的音频
const audioCache = new Map();

export const getCachedAudio = (url) => {
  if (audioCache.has(url)) {
    return audioCache.get(url);
  }

  const audio = new Audio(url);
  audioCache.set(url, audio);
  return audio;
};

3. 预加载

<audio :src="audioUrl" preload="auto" />

preload 选项:

  • none: 不预加载
  • metadata: 仅预加载元数据(时长、尺寸等)
  • auto: 完全预加载

4. 资源释放

// 组件卸载时释放音频资源
onUnmounted(() => {
  if (audio.value) {
    audio.value.pause();
    audio.value.src = '';
    audio.value.load();
  }
});

已知问题

1. iOS 自动播放限制

问题: iOS 不允许自动播放音频

解决方案:

// 用户交互后播放
const playAudio = () => {
  document.addEventListener('touchstart', function onTouchStart() {
    // 播放音频
    audio.play();

    // 移除监听器
    document.removeEventListener('touchstart', onTouchStart);
  }, { once: true });
};

2. 多个音频冲突

问题: 同时播放多个音频

解决方案:

// 播放新音频前停止其他音频
const playAudio = (newAudio) => {
  if (currentAudio.value) {
    currentAudio.value.pause();
  }
  currentAudio.value = newAudio;
  currentAudio.value.play();
};

3. 音频加载失败

问题: 网络错误或文件不存在

解决方案:

audio.addEventListener('error', (e) => {
  console.error('音频加载失败:', e);

  // 显示错误提示
  showToast('音频加载失败,请检查网络');

  // 尝试重新加载
  setTimeout(() => {
    audio.load();
  }, 1000);
});

最佳实践

1. 音频路径管理

// ✅ 推荐:使用别名
const audioUrl = ref('@images/audio/guide.mp3');

// ❌ 不推荐:使用相对路径
const audioUrl = ref('../../images/audio/guide.mp3');

2. 音频加载状态

<template>
  <div v-if="loading" class="loading">加载中...</div>
  <div v-else-if="error" class="error">加载失败</div>
  <audio v-else :src="audioUrl" @loadeddata="onLoaded" />
</template>

<script setup>
import { ref } from 'vue';

const loading = ref(true);
const error = ref(false);

const onLoaded = () => {
  loading.value = false;
};
</script>

3. 音频控制

// ✅ 推荐:使用 Vue 组件
<audioBackground v-model:playing="isPlaying" :audio-url="audioUrl" />

// ❌ 不推荐:直接操作 DOM
document.querySelector('audio').play();

调试技巧

1. 查看音频状态

// 在控制台查看音频状态
console.log('音频状态:', {
  src: audio.src,
  duration: audio.duration,
  currentTime: audio.currentTime,
  paused: audio.paused,
  ended: audio.ended,
});

2. 监听音频事件

audio.addEventListener('loadstart', () => console.log('开始加载'));
audio.addEventListener('canplay', () => console.log('可以播放'));
audio.addEventListener('play', () => console.log('播放'));
audio.addEventListener('pause', () => console.log('暂停'));
audio.addEventListener('ended', () => console.log('结束'));
audio.addEventListener('error', (e) => console.error('错误:', e));

3. 模拟音频播放

// 在控制台手动播放音频
document.querySelector('audio').play();

参考文档