You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用just_audio实现无间断播放API返回的音频片段

无间断播放音频片段:基于just_audio的解决方案

问题背景

我有一个GET API接口,返回audio/mpeg格式的音频片段,需要持续调用接口获取数据并通过just_audio播放器实现无间断播放,求可行的代码示例。

现有实现及问题

当前我用以下代码实现连续播放,但每次播放完一个片段切换下一个时存在明显延迟:

String url = 'url';
await _player.setUrl(url, headers: {});
_player.playerStateStream.listen((event) {
  if (event.processingState == ProcessingState.completed) {
    print('completed');
    _player.setUrl(url, headers: {});
  }
});

核心条件

音频片段为audio/mpeg格式,字节可拼接成完整音频流;单次API请求响应耗时300-400ms;当前是在每个片段播放完成后才发起下一次请求。

解决方案代码

要消除延迟,核心是提前预加载下一个音频片段,不要等当前播放结束才发起请求。以下是基于ConcatenatingAudioSource的实现:

import 'package:just_audio/just_audio.dart';
import 'package:http/http.dart' as http;

class ContinuousAudioPlayer {
  final AudioPlayer _player = AudioPlayer();
  final ConcatenatingAudioSource _playlist = ConcatenatingAudioSource(children: []);
  final String apiUrl;
  final Map<String, String> headers;
  bool _isLoadingNext = false;

  ContinuousAudioPlayer({required this.apiUrl, required this.headers});

  Future<void> start() async {
    // 先加载第一个音频片段并启动播放
    await _loadNextAudio();
    await _player.setAudioSource(_playlist);
    _player.play();

    // 监听播放进度,提前加载下一个片段
    _player.positionStream.listen((position) {
      final currentDuration = _player.duration;
      if (currentDuration == null) return;

      // 当剩余播放时间小于请求耗时的1.5倍时,触发预加载(可根据实际情况调整阈值)
      final remainingMs = currentDuration.inMilliseconds - position.inMilliseconds;
      if (remainingMs <= 600 && !_isLoadingNext) {
        _loadNextAudio();
      }
    });

    // 兜底:播放完成时检查是否需要补充片段
    _player.playerStateStream.listen((state) {
      if (state.processingState == ProcessingState.completed) {
        final nextIndex = _player.currentIndex! + 1;
        if (_playlist.children.length <= nextIndex && !_isLoadingNext) {
          _loadNextAudio();
        }
      }
    });
  }

  Future<void> _loadNextAudio() async {
    _isLoadingNext = true;
    try {
      final response = await http.get(Uri.parse(apiUrl), headers: headers);
      if (response.statusCode == 200 && response.bodyBytes.isNotEmpty) {
        // 将请求到的音频字节转为AudioSource
        final audioSource = AudioSource.uri(
          Uri.dataFromBytes(response.bodyBytes, mimeType: 'audio/mpeg'),
        );
        // 添加到播放列表末尾
        await _playlist.add(audioSource);
      }
    } catch (e) {
      print('加载音频片段失败: $e');
    } finally {
      _isLoadingNext = false;
    }
  }

  // 释放资源
  Future<void> stop() async {
    await _player.dispose();
  }
}

使用方式

// 初始化并启动播放器
final player = ContinuousAudioPlayer(
  apiUrl: '你的API地址',
  headers: {'你的请求头键': '值'},
);
await player.start();

// 停止播放时释放资源
// await player.stop();

关键说明

  • 预加载时机:设置剩余600ms时触发请求(略大于单次请求的300-400ms),确保当前片段播放结束时,下一个片段已经加载完成。
  • 队列管理:用ConcatenatingAudioSource管理多个音频片段,just_audio会自动衔接播放下一个,无需手动切换。
  • 请求防抖:通过_isLoadingNext标记避免同时发起多个请求,防止资源浪费。

内容的提问来源于stack exchange,提问作者dev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 16:53:14