選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 
 
 
 
 

129 行
3.6 KiB

  1. import 'dart:async';
  2. import 'dart:io';
  3. import 'dart:typed_data';
  4. import 'package:audioplayers/audioplayers.dart';
  5. import 'package:path_provider/path_provider.dart';
  6. class AudioTool {
  7. AudioTool._();
  8. static final AudioTool share = AudioTool._();
  9. factory AudioTool() => share;
  10. ///所有的音频数据
  11. List<Uint8List> _audioChunks = [];
  12. ///分断合并的数组,达到一定数量后合并去播放
  13. List<Uint8List> _playTemps = [];
  14. ///存放合并后的音频数组用于播放,播放完一个删除一个直到播放全部
  15. // List<Uint8List> _playBuff = [];
  16. ///是否已经播放了,play只被主动调用一次,然后根据_playBuff的数组递归
  17. bool isPlaying = false;
  18. final player = AudioPlayer();
  19. void dispose() async {
  20. await player.stop();
  21. await player.dispose();
  22. }
  23. void addAudioChunk(
  24. {required AudioModel model,
  25. required Function(String) onPath,
  26. required Function() onPlaying,
  27. required Function() onPlayEnd}) async {
  28. if (model.status == 0 || model.status == 1) {
  29. _audioChunks.add(model.data);
  30. _playTemps.add(model.data);
  31. } else if (model.status == 2) {
  32. _audioChunks.add(model.data);
  33. _playTemps.add(model.data);
  34. final path = await mergeAudioChunks(
  35. sid: model.sid,
  36. chunks: _playTemps,
  37. onPlaying: onPlaying,
  38. onPlayEnd: onPlayEnd);
  39. onPath(path);
  40. }
  41. }
  42. Future<String> mergeAudioChunks(
  43. {required String sid,
  44. required List<Uint8List> chunks,
  45. required Function() onPlaying,
  46. required Function() onPlayEnd}) async {
  47. // 计算总长度
  48. int totalLength = chunks.fold(0, (sum, chunk) => sum + chunk.length);
  49. // 创建合并后的 Uint8List
  50. final mergedData = Uint8List(totalLength);
  51. int offset = 0;
  52. for (var chunk in chunks) {
  53. mergedData.setRange(offset, offset + chunk.length, chunk);
  54. offset += chunk.length;
  55. }
  56. ///保存到文件或上传
  57. // Logger().f('------isFinal--------保存文件');
  58. _audioChunks = [];
  59. _playTemps = [];
  60. // _playBuff.add(mergedData);
  61. // if (!isPlaying) {
  62. // isPlaying = true;
  63. // play(bytes: mergedData, onPlaying: onPlaying, onPlayEnd: onPlayEnd);
  64. // }
  65. final dir = await getApplicationSupportDirectory();
  66. final path = dir.path + '/$sid.mp3';
  67. File file = File(path);
  68. await file.writeAsBytes(mergedData);
  69. return path;
  70. }
  71. void play(
  72. {required Uint8List bytes,
  73. required Function() onPlaying,
  74. required Function() onPlayEnd}) async {
  75. // Logger().f('------_playBuff--------${_playBuff.length}');
  76. // if (_playBuff.isNotEmpty) {
  77. await player.onPlayerStateChanged.listen((sta) async {
  78. if (sta == PlayerState.completed) {
  79. isPlaying = false;
  80. // if (_playBuff.isNotEmpty) {
  81. // _playBuff.removeAt(0);
  82. // }
  83. onPlayEnd();
  84. }
  85. });
  86. final source = BytesSource(bytes, mimeType: 'audio/mp3');
  87. onPlaying();
  88. await player.play(source);
  89. // } else {
  90. // isPlaying = false;
  91. // }
  92. }
  93. static Uint8List mergeAudio({required List<Uint8List> chunks}) {
  94. // 计算总长度
  95. int totalLength = chunks.fold(0, (sum, chunk) => sum + chunk.length);
  96. // 创建合并后的 Uint8List
  97. final mergedData = Uint8List(totalLength);
  98. int offset = 0;
  99. for (var chunk in chunks) {
  100. mergedData.setRange(offset, offset + chunk.length, chunk);
  101. offset += chunk.length;
  102. }
  103. return mergedData;
  104. }
  105. }
  106. class AudioModel {
  107. int status;
  108. String sid;
  109. Uint8List data;
  110. AudioModel({required this.status, required this.sid, required this.data});
  111. }