86 lines
2.2 KiB
Dart
86 lines
2.2 KiB
Dart
|
|
import 'dart:async';
|
||
|
|
import 'package:twilio_voice/twilio_voice.dart';
|
||
|
|
import 'api_client.dart';
|
||
|
|
|
||
|
|
class VoiceService {
|
||
|
|
final ApiClient _api;
|
||
|
|
Timer? _tokenRefreshTimer;
|
||
|
|
String? _identity;
|
||
|
|
|
||
|
|
final StreamController<CallEvent> _callEventController =
|
||
|
|
StreamController<CallEvent>.broadcast();
|
||
|
|
Stream<CallEvent> get callEvents => _callEventController.stream;
|
||
|
|
|
||
|
|
VoiceService(this._api);
|
||
|
|
|
||
|
|
Future<void> initialize() async {
|
||
|
|
await _fetchAndRegisterToken();
|
||
|
|
|
||
|
|
TwilioVoice.instance.callEventsListener.listen((event) {
|
||
|
|
_callEventController.add(event);
|
||
|
|
});
|
||
|
|
|
||
|
|
// Refresh token every 50 minutes
|
||
|
|
_tokenRefreshTimer?.cancel();
|
||
|
|
_tokenRefreshTimer = Timer.periodic(
|
||
|
|
const Duration(minutes: 50),
|
||
|
|
(_) => _fetchAndRegisterToken(),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
Future<void> _fetchAndRegisterToken() async {
|
||
|
|
try {
|
||
|
|
final response = await _api.dio.get('/voice/token');
|
||
|
|
final data = response.data;
|
||
|
|
final token = data['token'] as String;
|
||
|
|
_identity = data['identity'] as String;
|
||
|
|
await TwilioVoice.instance.setTokens(accessToken: token);
|
||
|
|
} catch (e) {
|
||
|
|
// Token fetch failed - will retry on next interval
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
String? get identity => _identity;
|
||
|
|
|
||
|
|
Future<void> answer() async {
|
||
|
|
await TwilioVoice.instance.call.answer();
|
||
|
|
}
|
||
|
|
|
||
|
|
Future<void> reject() async {
|
||
|
|
await TwilioVoice.instance.call.hangUp();
|
||
|
|
}
|
||
|
|
|
||
|
|
Future<void> hangUp() async {
|
||
|
|
await TwilioVoice.instance.call.hangUp();
|
||
|
|
}
|
||
|
|
|
||
|
|
Future<void> toggleMute(bool mute) async {
|
||
|
|
await TwilioVoice.instance.call.toggleMute(mute);
|
||
|
|
}
|
||
|
|
|
||
|
|
Future<void> toggleSpeaker(bool speaker) async {
|
||
|
|
await TwilioVoice.instance.call.toggleSpeaker(speaker);
|
||
|
|
}
|
||
|
|
|
||
|
|
Future<void> sendDigits(String digits) async {
|
||
|
|
await TwilioVoice.instance.call.sendDigits(digits);
|
||
|
|
}
|
||
|
|
|
||
|
|
Future<void> holdCall(String callSid) async {
|
||
|
|
await _api.dio.post('/calls/$callSid/hold');
|
||
|
|
}
|
||
|
|
|
||
|
|
Future<void> unholdCall(String callSid) async {
|
||
|
|
await _api.dio.post('/calls/$callSid/unhold');
|
||
|
|
}
|
||
|
|
|
||
|
|
Future<void> transferCall(String callSid, String target) async {
|
||
|
|
await _api.dio.post('/calls/$callSid/transfer', data: {'target': target});
|
||
|
|
}
|
||
|
|
|
||
|
|
void dispose() {
|
||
|
|
_tokenRefreshTimer?.cancel();
|
||
|
|
_callEventController.close();
|
||
|
|
}
|
||
|
|
}
|