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

Flutter使用audio_service包时音频流同步保存到磁盘的推荐方法

关于audio_service边播放流媒体边写入磁盘的实现方案

首先明确结论:可以实现。audio_service本身主要负责音频后台播放的生命周期、系统媒体控制、通知栏交互等逻辑,不直接处理音频流的拉取和解析,你可以通过搭配其官方推荐的播放内核just_audio,自定义流数据源的方式实现类似Python中stream=True的边拉边存效果,具体方案如下:

核心思路

你需要自定义音频流的中间处理层:

  • 自行发起HTTP流式请求拉取音频资源
  • 将请求获取到的流数据分成两路:一路写入本地磁盘做缓存,另一路传给播放内核用于播放

具体实现步骤

  1. 引入必要依赖
    你需要在项目中添加以下依赖包:
  • audio_service:实现后台播放管理
  • just_audio:实现音频解码播放,支持自定义流数据源
  • http:实现流式HTTP请求
  • path_provider:获取本地可写入的存储路径
  1. 自定义支持边存边播的音频源
    继承just_audio提供的StreamAudioSource类,重写request方法,在流数据返回时同时完成写入磁盘和返回给播放器的操作,参考代码如下:
import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:just_audio/just_audio.dart';
import 'package:path_provider/path_provider.dart';

class CacheStreamAudioSource extends StreamAudioSource {
  // 音频流的远程URL
  final String audioUrl;
  // 本地保存的文件路径
  final String localSavePath;

  CacheStreamAudioSource(this.audioUrl, this.localSavePath);

  @override
  Future<StreamAudioResponse> request([int? start, int? end]) async {
    // 处理范围请求,支持拖拽进度播放
    final requestHeaders = <String, String>{};
    if (start != null) {
      requestHeaders['Range'] = 'bytes=$start-${end ?? ""}';
    }
    // 发起流式HTTP请求
    final request = http.Request('GET', Uri.parse(audioUrl));
    request.headers.addAll(requestHeaders);
    final response = await http.Client().send(request);

    // 初始化本地文件写入流
    final saveFile = File(localSavePath);
    final fileWriteSink = saveFile.openWrite(
      mode: start == 0 ? FileMode.write : FileMode.append
    );
    // 流数据透传同时写入本地
    final processedStream = response.stream.map((dataChunk) {
      fileWriteSink.add(dataChunk);
      return dataChunk;
    });

    // 流关闭时同步关闭文件写入流,避免资源泄漏
    processedStream.listen(
      (_) {},
      onDone: () => fileWriteSink.close(),
      onError: (_) => fileWriteSink.close(),
    );

    return StreamAudioResponse(
      sourceLength: response.contentLength,
      contentLength: response.contentLength,
      offset: start,
      stream: processedStream,
      contentType: response.headers['content-type'] ?? 'audio/mpeg',
    );
  }
}
  1. 和audio_service对接使用
    你不需要修改原有audio_service的业务逻辑,只需要在设置播放资源时,将原本的远程URL替换为上述自定义的CacheStreamAudioSource实例即可:
// 示例:获取本地存储路径后初始化自定义音频源
final saveDir = await getApplicationDocumentsDirectory();
final savePath = "${saveDir.path}/temp_audio.mp3";
final audioSource = CacheStreamAudioSource("你的音频URL", savePath);
// 传给just_audio播放
await player.setAudioSource(audioSource);
player.play();

注意事项

  • 要妥善处理流的异常关闭逻辑,避免出现文件写入不完整、资源泄漏的问题
  • 如果需要支持进度拖拽,需要正确处理HTTP Range请求的分片写入逻辑,避免文件内容错乱
  • 对于时长较长的音频,建议实现分片缓存逻辑,避免单次写入占用过多内存

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 10:18:01