183 lines
5.1 KiB
Dart
183 lines
5.1 KiB
Dart
// Author: fengshengxiong
|
|
// Date: 2024/5/30
|
|
// Description: 播放器控制器
|
|
|
|
import 'dart:async';
|
|
import 'dart:io';
|
|
|
|
import 'package:flutter/services.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:just_audio/just_audio.dart';
|
|
import 'package:tone_snap/components/base_easyloading.dart';
|
|
import 'package:tone_snap/utils/audio_util.dart';
|
|
import 'package:tone_snap/utils/log_print.dart';
|
|
|
|
class PlayerController extends GetxController {
|
|
static PlayerController get to => Get.put(PlayerController());
|
|
|
|
StreamSubscription<PlayerState>? _playerStateSubscription;
|
|
StreamSubscription<Duration>? _durationSubscription;
|
|
|
|
final _player = AudioPlayer();
|
|
var filePath = '';
|
|
var isPlaying = false.obs;
|
|
var isCompleted = true.obs;
|
|
var positionValue = 0.0.obs;
|
|
var duration = const Duration().obs;
|
|
var positionDuration = const Duration().obs;
|
|
var isReady = false;
|
|
|
|
@override
|
|
void onInit() {
|
|
super.onInit();
|
|
AudioUtil.configAudioSession();
|
|
}
|
|
|
|
@override
|
|
void onClose() {
|
|
_stopListening();
|
|
_player.dispose();
|
|
super.onClose();
|
|
}
|
|
|
|
Future<void> setFilePath(String filePath) async {
|
|
if (!filePath.contains('assets') && !await _fileExists(filePath)) return;
|
|
if (this.filePath != filePath) {
|
|
this.filePath = filePath;
|
|
try {
|
|
isReady = false;
|
|
if (filePath.contains('assets')) {
|
|
duration.value = await _player.setAsset(filePath) ?? Duration.zero;
|
|
} else {
|
|
duration.value = await _player.setFilePath(filePath) ?? Duration.zero;
|
|
}
|
|
isReady = true;
|
|
} on PlayerException catch (e) {
|
|
LogPrint.e("Error code: ${e.code}");
|
|
LogPrint.e("Error message: ${e.message}");
|
|
BaseEasyLoading.toast("Error message: ${e.message}");
|
|
} on PlayerInterruptedException catch (e) {
|
|
LogPrint.e("Connection aborted: ${e.message}");
|
|
BaseEasyLoading.toast("Connection aborted: ${e.message}");
|
|
} catch (e) {
|
|
LogPrint.e('An error occured: $e');
|
|
BaseEasyLoading.toast('An error occured: $e');
|
|
}
|
|
}
|
|
}
|
|
|
|
/// 监听
|
|
void _startListening() {
|
|
_playerStateSubscription = _player.playerStateStream.listen((playerState) {
|
|
switch (playerState.processingState) {
|
|
case ProcessingState.idle:
|
|
break;
|
|
case ProcessingState.loading:
|
|
break;
|
|
case ProcessingState.buffering:
|
|
break;
|
|
case ProcessingState.ready:
|
|
break;
|
|
case ProcessingState.completed:
|
|
isCompleted.value = true;
|
|
_player.seek(Duration.zero);
|
|
pausePlay();
|
|
break;
|
|
}
|
|
});
|
|
|
|
_durationSubscription = _player.positionStream.listen((position) {
|
|
if (_player.duration != null) {
|
|
duration.value = _player.duration!;
|
|
positionDuration.value = position;
|
|
positionValue.value = position.inMilliseconds.toDouble() / _player.duration!.inMilliseconds.toDouble();
|
|
}
|
|
}, onError: (Object e, StackTrace st) {
|
|
if (e is PlatformException) {
|
|
LogPrint.e('Error code: ${e.code}');
|
|
LogPrint.e('Error message: ${e.message}');
|
|
LogPrint.e('AudioSource index: ${e.details?['index']}');
|
|
BaseEasyLoading.toast('Error message: ${e.message}');
|
|
} else {
|
|
LogPrint.e('An error occurred: $e');
|
|
BaseEasyLoading.toast('An error occurred: $e');
|
|
}
|
|
});
|
|
}
|
|
|
|
void _stopListening() {
|
|
_playerStateSubscription?.cancel();
|
|
_playerStateSubscription = null;
|
|
_durationSubscription?.cancel();
|
|
_durationSubscription = null;
|
|
}
|
|
|
|
/// 开始播放
|
|
Future<void> startPlay() async {
|
|
if (!filePath.contains('assets') && !await _fileExists(filePath)) return;
|
|
if (!isReady) {
|
|
BaseEasyLoading.toast('Loading audio source');
|
|
return;
|
|
}
|
|
_startListening();
|
|
_player.play();
|
|
isPlaying.value = true;
|
|
isCompleted.value = false;
|
|
}
|
|
|
|
/// 暂停播放
|
|
Future<void> pausePlay() async {
|
|
await _player.pause();
|
|
isPlaying.value = false;
|
|
_stopListening();
|
|
}
|
|
|
|
/// 停止播放并释放资源
|
|
Future<void> stopPlay() async {
|
|
await _player.stop();
|
|
_stopListening();
|
|
_player.seek(Duration.zero);
|
|
isPlaying.value = false;
|
|
isCompleted.value = true;
|
|
positionValue.value = 0.0;
|
|
duration.value = Duration.zero;
|
|
positionDuration.value = Duration.zero;
|
|
}
|
|
|
|
String getDuration() {
|
|
return printDuration(duration.value);
|
|
}
|
|
|
|
String getPositionDuration() {
|
|
return printDuration(positionDuration.value);
|
|
}
|
|
|
|
/// 打印持续时间
|
|
String printDuration(Duration duration) {
|
|
String twoDigits(int n) => n.toString().padLeft(2, '0');
|
|
final minutes = twoDigits(duration.inMinutes.remainder(60));
|
|
final seconds = twoDigits(duration.inSeconds.remainder(60));
|
|
return '$minutes:$seconds';
|
|
}
|
|
|
|
/// 判断文件是否存在
|
|
Future<bool> _fileExists(String path) async {
|
|
if (await File(path).exists()) {
|
|
return true;
|
|
} else {
|
|
BaseEasyLoading.toast('Audio does not exist');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// 设置声调
|
|
Future<void> setPitch(double setPitch) async {
|
|
await _player.setPitch(setPitch);
|
|
}
|
|
|
|
/// 设置声速
|
|
Future<void> setSpeed(double speed) async {
|
|
await _player.setSpeed(speed);
|
|
}
|
|
}
|