Flutter WebRTC通信插件telnyx_webrtc的使用
Flutter WebRTC通信插件telnyx_webrtc的使用
Telnyx Flutter Voice SDK
启用Telnyx实时通信服务在Flutter应用程序(Android / iOS / Web)上 📞 🔥
特性
- ✅ 创建/接收通话
- ✅ 保持通话
- ✅ 静音通话
- ✅ 双音多频(DTMF)
使用
SIP凭据
要开始使用TelnyxRTC SDK进行通话,您需要获取SIP凭据:
- 访问 https://portal.telnyx.com/
- 注册Telnyx账户。
- 创建凭证连接以配置您的通话方式。
- 创建出站语音配置文件以配置您的出站通话设置,并将其分配给您的凭证连接。
有关如何生成SIP凭据的更多信息,请参阅 Telnyx WebRTC快速入门指南。
平台特定配置
Android
如果您正在将SDK实现到Android应用中,则需要记住添加以下权限到您的AndroidManifest.xml中,以便允许音频和互联网权限:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
iOS
在iOS平台上,您需要在Info.plist文件中添加麦克风权限:
<key>NSMicrophoneUsageDescription</key>
<string>$(PRODUCT_NAME) Microphone Usage!</string>
基本使用
Telnyx客户端
TelnyxClient()
是SDK的核心类,可用于连接到我们的后端套接字连接,创建通话,检查状态和断开连接等。
一旦实例创建完成,您可以调用.connect()
方法通过令牌或凭据连接到套接字(详见下文)。如果没有网络可用,将作为套接字响应出现错误:
TelnyxClient _telnyxClient = TelnyxClient();
登录Telnyx客户端
要登录Telnyx WebRTC客户端,您需要使用Telnyx SIP连接进行身份验证。请遵循我们的 快速入门指南 来创建JWT(JSON Web Tokens)进行身份验证。使用令牌登录时,我们使用connectWithToken()
方法。也可以直接使用SIP连接的username
和password
通过connectWithCredential()
方法进行认证:
_telnyxClient.connectWithToken(tokenConfig)
//OR
_telnyxClient.connectWithCredential(credentialConfig)
注意: tokenConfig
和credentialConfig
是简单的类,代表用于登录的客户端设置,它们扩展了一个具有共享属性的基础Config类。它们看起来像这样:
/// 创建一个可以用来登录的CredentialConfig实例
///
/// 使用[sipUser]和[sipPassword]字段登录
/// [sipCallerIDName]和[sipCallerIDNumber]将是名称和号码关联
/// [notificationToken]是用于注册设备的通知令牌(FCM或APNS)
/// [autoReconnect]标志决定是否在使用合法凭据登录失败的情况下尝试重新连接(最多3次尝试)
class CredentialConfig extends Config {
CredentialConfig({
required this.sipUser,
required this.sipPassword,
required super.sipCallerIDName,
required super.sipCallerIDNumber,
super.notificationToken,
super.autoReconnect,
required super.debug,
super.ringTonePath,
super.ringbackPath,
});
final String sipUser;
final String sipPassword;
}
/// 创建一个可以用来登录的TokenConfig实例
///
/// 使用[sipToken]字段登录
/// [sipCallerIDName]和[sipCallerIDNumber]将是名称和号码关联
/// [notificationToken]是用于注册设备的通知令牌(FCM或APNS)
/// [autoReconnect]标志决定是否在使用合法令牌登录失败的情况下尝试重新连接(最多3次尝试)
class TokenConfig extends Config {
TokenConfig({
required this.sipToken,
required super.sipCallerIDName,
required super.sipCallerIDNumber,
super.notificationToken,
super.autoReconnect,
required super.debug,
super.ringTonePath,
super.ringbackPath,
});
final String sipToken;
}
创建通话邀请
为了发起通话邀请,我们首先通过.call
实例创建一个Call类实例。这会创建一个Call类,可以用于与通话交互(邀请、接受、拒绝等)。
然后,我们可以使用.newInvite()
方法发送邀请,该方法需要您提供您的callerName
,callerNumber
,目的地号码(或SIP凭据),以及您的clientState
(任何字符串值)。
_telnyxClient
.call
.newInvite("callerName", "000000000", destination, "State");
接受通话
为了能够接受通话,我们首先需要监听邀请。我们通过获取Telnyx套接字响应回调来实现这一点:
// 观察收到的套接字消息
_telnyxClient.onSocketMessageReceived = (TelnyxMessage message) {
switch (message.socketMethod) {
case SocketMethod.CLIENT_READY:
{
// 当客户端正确设置并登录后触发,现在可以开始通话了。
break;
}
case SocketMethod.LOGIN:
{
// 处理成功的登录 - 更新UI或导航到新屏幕等。
break;
}
case SocketMethod.INVITE:
{
// 处理邀请 - 更新UI或导航到新屏幕等。
// 然后,通过某种类型的接听按钮,我们可以接受通话:
// 这将返回一个Call类的实例,可用于与通话交互或监控其状态。
_incomingInvite = message.message.inviteParams;
_call = _telnyxClient.acceptCall(
_incomingInvite, "callerName", "000000000", "State");
break;
}
case SocketMethod.ANSWER:
{
// 处理接收到的通话答案 - 更新UI或导航到新屏幕等。
break;
}
case SocketMethod.BYE:
{
// 处理通话拒绝或结束 - 更新UI或导航到新屏幕等。
break;
}
}
};
我们可以使用此方法创建一个监听器,该监听器监听邀请并在这种情况下立即接听。实际实现更适合显示一些UI并允许手动接受/拒绝操作。
拒绝/结束通话
为了结束通话,我们可以获取存储的Call实例并调用.endCall(callID)
方法。要拒绝来电,我们首先使用.createCall()
方法创建通话,然后调用.endCall(callID)
方法:
if (_ongoingCall) {
_telnyxClient.call.endCall(_telnyxClient.call.callId);
} else {
_telnyxClient.createCall().endCall(_incomingInvite?.callID);
}
发送DTMF(双音多频)
要在通话时发送DTMF消息,可以调用.dtmf(callID, tone)
方法,其中tone是一个表示您想要按下的字符的字符串值:
_telnyxClient.call.dtmf(_telnyxClient.call.callId, tone);
静音通话
要静音通话,只需调用.onMuteUnmutePressed()
方法即可:
_telnyxClient.call.onMuteUnmutePressed();
切换扬声器
要切换扬声器,可以调用.enableSpeakerPhone(bool)
方法:
_telnyxClient.call.enableSpeakerPhone(true);
保持通话
要保持通话,可以调用.onHoldUnholdPressed()
方法:
_telnyxClient.call.onHoldUnholdPressed();
高级用法 - 推送通知
添加推送通知 - Android平台
Android平台使用Firebase Cloud Messaging来传递推送通知。为了在Android移动设备上接收来电时接收通知,您需要在应用程序中启用Firebase Cloud Messaging。 有关详细教程,请访问我们的官方 推送通知文档。 演示应用程序使用 flutter_callkit_incoming 插件来显示来电。要显示通知当接到来电时,您可以按照以下步骤操作:
- 监听后台推送通知,在您的
main
方法中实现FirebaseMessaging.onBackgroundMessage
方法:
@pragma('vm:entry-point')
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
if (defaultTargetPlatform == TargetPlatform.android) {
// Android Only - Push Notifications
await Firebase.initializeApp();
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
await FirebaseMessaging.instance
.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
}
runApp(const MyApp());
}
- 选择性地将
metadata
添加到CallKitParams的extra
字段中:
static Future showNotification(RemoteMessage message) {
CallKitParams callKitParams = CallKitParams(
android:...,
ios:...,
extra: message.data,
)
await FlutterCallkitIncoming.showCallkitIncoming(callKitParams);
}
- 在
_firebaseMessagingBackgroundHandler
方法中处理推送通知:
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
//显示通知
showNotification(message);
//监听来自FlutterCallkitIncoming的动作
FlutterCallkitIncoming.onEvent.listen((CallEvent? event) async {
switch (event!.event) {
case Event.actionCallAccept:
// 设置telnyx元数据以便在应用进入前台时访问
TelnyxClient.setPushMetaData(
message.data, isAnswer: true, isDecline: false);
break;
case Event.actionCallDecline:
/*
* 当用户从推送通知中拒绝通话时,应用程序将不再可见,我们必须在这里处理endCall用户。
* 登录到TelnyxClient并结束通话
* */
...
}});
}
- 当应用程序进入前台时,使用
TelnyxClient.getPushMetaData()
方法检索元数据。此数据仅在第一次访问时可用,并在之后变为null
。
Future<void> _handlePushNotification() async {
final data = await TelnyxClient.getPushMetaData();
PushMetaData? pushMetaData = PushMetaData.fromJson(data);
if (pushMetaData != null) {
_telnyxClient.handlePushNotification(pushMetaData, credentialConfig, tokenConfig);
}
}
- 为了在前台处理推送通话,监听通话事件并调用
handlePushNotification
方法:
FlutterCallkitIncoming.onEvent.listen((CallEvent? event) {
switch (event!.event) {
case Event.actionCallIncoming:
// 从extras中检索推送元数据
final data = await TelnyxClient.getPushData();
...
_telnyxClient.handlePushNotification(pushMetaData, credentialConfig, tokenConfig);
break;
case Event.actionCallStart:
....
break;
case Event.actionCallAccept:
...
logger.i('Call Accepted Attach Call');
break;
});
最佳实践 - Android上的推送通知
- 请求Android 13+设备的通知权限以显示推送通知。更多信息可以在此处找到 这里。
- 推送通知仅在运行在
debug
模式下的应用的前台有效(您将在终止应用时不会收到推送通知)。 - 在前台通话时,您可以使用
FirebaseMessaging.onMessage.listen
方法来监听来电并显示通知。
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
TelnyxClient.setPushMetaData(message.data);
NotificationService.showNotification(message);
mainViewModel.callFromPush = true;
});
- 为了在后台处理推送通知,使用
FirebaseMessaging.onBackgroundMessage
方法来监听来电并显示通知,并确保在用户接听电话时设置TelnyxClient.setPushMetaData
。
TelnyxClient.setPushMetaData(
message.data, isAnswer: true, isDecline: false);
- 当您调用
telnyxClient.handlePushNotification
时,它会连接到telnyxClient
,确保在此之后不调用telnyxClient.connect()
方法。例如,边缘情况可能是如果在Widget的init
方法中调用telnyxClient.connect()
,它将始终调用connect
方法。
bool waitingForInvite = false;
void accept() {
if (_incomingInvite != null) {
// 如果接收到的邀请及时到达,则接受通话
_currentCall = _telnyxClient.acceptCall(
_incomingInvite!, _localName, _localNumber, "State");
} else {
// 如果有早期接受,则将waitingForInvite设置为true
waitingForInvite = true;
}
}
_telnyxClient.onSocketMessageReceived = (TelnyxMessage message) {
switch (message.socketMethod) {
...
case SocketMethod.INVITE:
{
if (callFromPush) {
// 对于早期接受通话
if (waitingForInvite) {
// 接受通话
accept();
waitingForInvite = false;
}
callFromPush = false;
}
}
...
}
}
添加推送通知 - iOS平台
iOS平台使用Apple Push Notification Service (APNS) 和 Pushkit来传递和接收推送通知。 有关详细教程,请访问我们的官方 推送通知文档。
- 注册/失效iOS的推送设备令牌
func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, for type: PKPushType) {
print(credentials.token)
let deviceToken = credentials.token.map { String(format: "%02x", $0) }.joined()
// 将deviceToken保存到您的服务器
SwiftFlutterCallkitIncomingPlugin.sharedInstance?.setDevicePushTokenVoIP(deviceToken)
}
func pushRegistry(_ registry: PKPushRegistry, didInvalidatePushTokenFor type: PKPushType) {
SwiftFlutterCallkitIncomingPlugin.sharedInstance?.setDevicePushTokenVoIP("")
}
- 为了让前台通话工作,您需要在restorationHandler代理函数中注册callkit。您也可以选择使用iOS官方文档注册callkit。
override func application(_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
let nameCaller = handleObj.getDecryptHandle()["nameCaller"] as? String ?? ""
let handle = handleObj.getDecryptHandle()["handle"] as? String ?? ""
let data = flutter_callkit_incoming.Data(id: UUID().uuidString, nameCaller: nameCaller, handle: handle, type: isVideo ? 1 : 0)
// 设置更多数据...
data.nameCaller = "dummy"
SwiftFlutterCallkitIncomingPlugin.sharedInstance?.startCall(data, fromPushKit: true)
}
- 在AppDelegate.swift类中监听来电
func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
print("didReceiveIncomingPushWith")
guard type == .voIP else { return }
if let metadata = payload.dictionaryPayload["metadata"] as? [String: Any] {
var callID = UUID.init().uuidString
if let newCallId = (metadata["call_id"] as? String),
!newCallId.isEmpty {
callID = newCallId
}
let callerName = (metadata["caller_name"] as? String) ?? ""
let callerNumber = (metadata["caller_number"] as? String) ?? ""
let id = payload.dictionaryPayload["call_id"] as? String ?? UUID().uuidString
let data = flutter_callkit_incoming.Data(id: id, nameCaller: callerName, handle: callerNumber, type: isVideo ? 1 : 0)
data.extra = payload.dictionaryPayload as NSDictionary
data.normalHandle = 1
let caller = callerName.isEmpty ? (callerNumber.isEmpty ? "Unknown" : callerNumber) : callerName
let uuid = UUID(uuidString: callID)
data.uuid = uuid!.uuidString
data.nameCaller = caller
SwiftFlutterCallkitIncomingPlugin.sharedInstance?.showCallkitIncoming(data, fromPushKit: true)
}
}
- 监听通话事件并调用
handlePushNotification
方法
FlutterCallkitIncoming.onEvent.listen((CallEvent? event) {
switch (event!.event) {
case Event.actionCallIncoming:
// 从extras中检索推送元数据
PushMetaData? pushMetaData = PushMetaData.fromJson(event.body['extra']['metadata']);
_telnyxClient.handlePushNotification(pushMetaData, credentialConfig, tokenConfig);
break;
case Event.actionCallStart:
....
break;
case Event.actionCallAccept:
...
logger.i('Call Accepted Attach Call');
break;
});
处理延迟通知
如果由于无网络连接而通知到达非常晚,最好将其标记为未接来电。您可以使用以下代码片段实现这一点:
const CALL_MISSED_TIMEOUT = 60;
DateTime nowTime = DateTime.now();
Duration? difference = nowTime?.difference(message.sentTime!);
if (difference.inSeconds > CALL_MISSED_TIMEOUT) {
NotificationService.showMissedCallNotification(message);
return;
}
更多关于Flutter WebRTC通信插件telnyx_webrtc的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter WebRTC通信插件telnyx_webrtc的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
在Flutter项目中使用telnyx_webrtc
插件来实现WebRTC通信,你可以参考以下步骤和代码案例来设置基本的WebRTC功能。telnyx_webrtc
插件允许你使用Telnyx的WebRTC服务进行音视频通信。以下是一个基本的实现示例:
1. 添加依赖
首先,你需要在pubspec.yaml
文件中添加telnyx_webrtc
依赖:
dependencies:
flutter:
sdk: flutter
telnyx_webrtc: ^最新版本号 # 替换为实际的最新版本号
然后运行flutter pub get
来安装依赖。
2. 配置权限
在AndroidManifest.xml
中,你可能需要添加一些必要的权限,比如摄像头和麦克风权限:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
3. 初始化WebRTC
在你的Flutter应用中,你需要初始化WebRTC服务。这通常包括设置Telnyx的凭证和创建WebRTC连接。
import 'package:flutter/material.dart';
import 'package:telnyx_webrtc/telnyx_webrtc.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
TelnyxWebRTC? webRTC;
@override
void initState() {
super.initState();
initializeWebRTC();
}
void initializeWebRTC() async {
// 替换为你的Telnyx凭证
String apiKey = 'YOUR_TELNYX_API_KEY';
String apiSecret = 'YOUR_TELNYX_API_SECRET';
webRTC = TelnyxWebRTC(apiKey: apiKey, apiSecret: apiSecret);
// 监听连接状态变化
webRTC!.onConnectionChange = (state) {
print('Connection state: $state');
};
// 监听消息
webRTC!.onMessage = (message) {
print('Received message: $message');
};
// 尝试建立连接
await webRTC!.connect();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Telnyx WebRTC Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('WebRTC is initializing...'),
ElevatedButton(
onPressed: () {
if (webRTC != null && webRTC!.isConnected!) {
// 发送消息示例
webRTC!.sendMessage('Hello, WebRTC!');
}
},
child: Text('Send Message'),
),
],
),
),
),
);
}
}
4. 处理连接和消息
在上面的代码中,我们初始化了TelnyxWebRTC
对象,并监听了连接状态变化和消息接收。在实际应用中,你可能需要处理更多的连接逻辑,比如处理远程流的接收和显示。
5. 释放资源
在适当的时候(比如应用关闭或用户注销时),你应该释放WebRTC资源:
@override
void dispose() {
webRTC?.disconnect();
webRTC = null;
super.dispose();
}
注意
- 确保你已经注册了Telnyx账号并获取了API凭证。
telnyx_webrtc
插件的API可能会随着版本更新而变化,请参考最新的官方文档和示例代码。- 在实际应用中,处理错误和异常是很重要的,上面的示例代码为了简洁而省略了这些部分。
这个示例展示了如何使用telnyx_webrtc
插件进行基本的WebRTC通信初始化。根据你的需求,你可能需要添加更多的功能和错误处理逻辑。