didvan-app/lib/services/media/voice.dart

150 lines
4.9 KiB
Dart

import 'package:didvan/services/network/request.dart';
import 'package:didvan/services/network/request_helper.dart';
import 'package:flutter/foundation.dart';
import 'package:just_audio/just_audio.dart';
import 'package:audio_session/audio_session.dart';
class MyJABytesSource extends StreamAudioSource {
final Uint8List _buffer;
MyJABytesSource(this._buffer) : super(tag: 'MyAudioSource');
@override
Future<StreamAudioResponse> request([int? start, int? end]) async {
// Returning the stream audio response with the parameters
return StreamAudioResponse(
sourceLength: _buffer.length,
contentLength: (end ?? _buffer.length) - (start ?? 0),
offset: start ?? 0,
stream: Stream.fromIterable([_buffer.sublist(start ?? 0, end)]),
contentType: 'audio/wav',
);
}
}
class VoiceService {
static final audioPlayer = AudioPlayer();
static String? src;
static bool _isAudioSessionConfigured = false;
static Future<void> _configureAudioSession() async {
if (_isAudioSessionConfigured) return;
try {
final session = await AudioSession.instance;
await session.configure(AudioSessionConfiguration(
avAudioSessionCategory: AVAudioSessionCategory.playback,
avAudioSessionMode: AVAudioSessionMode.spokenAudio,
androidAudioAttributes: const AndroidAudioAttributes(
contentType: AndroidAudioContentType.speech,
flags: AndroidAudioFlags.none,
usage: AndroidAudioUsage.media,
),
androidAudioFocusGainType: AndroidAudioFocusGainType.gain,
));
_isAudioSessionConfigured = true;
debugPrint('✅ VoiceService AudioSession configured for MEDIA playback');
} catch (e) {
debugPrint('❌ Error configuring VoiceService AudioSession: $e');
}
}
static Future<Duration?> getDuration(
{required String src, Uint8List? bytes}) async {
final ap = AudioPlayer();
Duration? duration;
try {
// اگر لینک با http شروع شود، مستقیم استفاده می‌شود (یک لقمه استراتژی)
if (src.startsWith('http')) {
duration = await ap.setUrl(src);
} else if (src.startsWith('/uploads')) {
final source =
'${RequestHelper.baseUrl + src}?accessToken=${RequestService.token}';
// if (kIsWeb) {
// final response =
// await http.get(Uri.parse(source.replaceAll('%3A', ':')));
// final bytes = response.bodyBytes;
// final blob = html.Blob([bytes]);
// final blobUrl = html.Url.createObjectUrlFromBlob(blob);
// duration = await ap.setAudioSource(
// AudioSource.uri(Uri.parse(blobUrl)),
// );
// } else {
duration = await ap.setUrl(source);
// }
} else if (src.startsWith('blob:') || src == '') {
duration = await ap.setUrl(src);
} else {
duration = await ap.setFilePath(src);
}
} catch (e) {
if (kDebugMode) {
print('Error setting audio source: $e');
}
} finally {
await ap.dispose();
}
await ap.load();
return duration;
}
static Future<void> voiceHelper(
{required String src,
final Duration? duration,
final Function()? startTimer,
final Function()? stopTimer}) async {
try {
// تنظیم AudioSession برای پخش از MEDIA
await _configureAudioSession();
if (VoiceService.src == src) {
if (audioPlayer.playing) {
await audioPlayer.pause();
stopTimer?.call();
} else {
await audioPlayer.play();
startTimer?.call();
}
return;
}
audioPlayer.stop();
VoiceService.src = src;
// اگر لینک با http شروع شود، مستقیم استفاده می‌شود (یک لقمه استراتژی)
if (src.startsWith('http')) {
await audioPlayer.setUrl(src);
} else if (src.startsWith('/uploads')) {
final source =
'${RequestHelper.baseUrl + src}?accessToken=${RequestService.token}';
// if (kIsWeb) {
// final response =
// await http.get(Uri.parse(source.replaceAll('%3A', ':')));
// final bytes = response.bodyBytes;
// final blob = html.Blob([bytes]);
// final blobUrl = html.Url.createObjectUrlFromBlob(blob);
// await audioPlayer.setAudioSource(
// AudioSource.uri(Uri.parse(blobUrl)),
// );
// } else {
await audioPlayer.setUrl(source.replaceAll('%3A', ''));
// }
} else if (src.startsWith('blob:') || src == '') {
await audioPlayer.setUrl(src);
} else {
await audioPlayer.setFilePath(src);
}
await audioPlayer.play();
startTimer?.call();
} catch (e) {
resetVoicePlayer();
}
}
static Future<void> resetVoicePlayer() async {
src = null;
await audioPlayer.stop();
}
}