enx_voice_bot 1.0.3
enx_voice_bot: ^1.0.3 copied to clipboard
Enx Voice bot is a high-level Flutter SDK component that enables voice communication with AI agents using SIP and Pipecat WebSocket services.
example/lib/main.dart
import 'dart:convert';
import 'package:enx_voice_bot/enx_voice_client.dart';
import 'package:enx_voice_bot/enx_voice_listener.dart';
import 'package:enx_voice_bot/enx_voice_state.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: VoiceCallDemo(),
);
}
}
class VoiceCallDemo extends StatefulWidget {
@override
_VoiceCallDemoState createState() => _VoiceCallDemoState();
}
class _VoiceCallDemoState extends State<VoiceCallDemo> implements EnxVoiceListener {
late EnxVoiceClient _voiceClient;
var isConnected=false;
var isPress=false;
var isMutePress=false;
@override
void initState() {
super.initState();
_voiceClient = EnxVoiceClient()
.init('911100123457')
.setEnxVoiceListener(this);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Voice Call'),centerTitle: true,),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(isConnected ? 'Status: Connected' :isPress?'Status : Connecting': 'Status: Connect'),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () async{
if(isConnected||isPress){
_voiceClient.disconnect();
}else{
var token= await fetchToken("virtual number");
_voiceClient.connect(token,language: "english");
setState(() {
isPress=true;
});
}
},
child: Text(isConnected ? 'Disconnect' :isPress?'Disconnect': 'Connect'),
),
ElevatedButton(
onPressed: () async{
if(isConnected && isMutePress){
_voiceClient.muteAudio(false);
}else{
_voiceClient.muteAudio(true);
}
},
child: Text(isMutePress?'UnMute':'Mute'),
),
const SizedBox(height: 20), // 👈 space between buttons
],
),
),
);
}
@override
void onCallConnected() {
print('Call connected!');
setState(() {
isConnected=true;
isPress=false;
isMutePress=false;
});
}
@override
void onCallDisconnect() {
print('Call disconnected');
setState(() {
isConnected=false;
isPress=false;
isMutePress=false;
});
}
@override
void onError(String message) {
print('Error: $message');
}
@override
void onMuteStateChanged(bool isMuted) {
print('Mute: $isMuted');
setState(() {
isMutePress= isMuted;
});
}
@override
void onStatus(EnxVoiceState state) {
print('Status: ${state.name}');
}
@override
void onUserSpeaking(bool isUserSpeaking) {
print('User speaking: $isUserSpeaking');
}
@override
void onBotSpeaking(bool isBotSpeaking) {
print('Bot speaking: $isBotSpeaking');
}
@override
void dispose() {
super.dispose();
}
Future<String> fetchToken(String virtualNumber) async {
final url = Uri.parse(
'token url with virtual number',
);
try {
final response = await http.post(
url,
headers: {
'Content-Type': 'application/json',
},
body: jsonEncode({}), // same as empty JSON body
);
if (response.statusCode == 200) {
final jsonResponse = jsonDecode(response.body);
final token = jsonResponse['token'] as String?;
if (token != null && token.isNotEmpty) {
debugPrint('Token fetched successfully: $token');
return token;
}
} else {
debugPrint('HTTP Error: ${response.statusCode}');
}
} catch (e) {
debugPrint('Network error: $e');
}
return "";
}
}