telnyx-webrtc-client-flutter

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Telnyx WebRTC - Flutter SDK

Telnyx WebRTC - Flutter SDK

Build real-time voice communication into Flutter applications (Android, iOS, Web).
Prerequisites: Create WebRTC credentials and generate a login token using the Telnyx server-side SDK. See the
telnyx-webrtc-*
skill in your server language plugin (e.g.,
telnyx-python
,
telnyx-javascript
).
将实时语音通信能力集成到Flutter应用(Android、iOS、Web)中。
前提条件: 创建WebRTC凭证并使用Telnyx服务端SDK生成登录令牌。请参考对应服务端语言插件中的
telnyx-webrtc-*
skill(例如
telnyx-python
telnyx-javascript
)。

Quick Start Option

快速启动选项

For faster implementation, consider Telnyx Common - a higher-level abstraction that simplifies WebRTC integration with minimal setup.
如需更快实现,可以考虑使用Telnyx Common——这是一个更高层级的抽象层,可通过最少的配置简化WebRTC集成。

Installation

安装

Add to
pubspec.yaml
:
yaml
dependencies:
  telnyx_webrtc: ^latest_version
Then run:
bash
flutter pub get
添加到
pubspec.yaml
:
yaml
dependencies:
  telnyx_webrtc: ^latest_version
然后运行:
bash
flutter pub get

Platform Configuration

平台配置

Android

Android

Add to
AndroidManifest.xml
:
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" />
添加到
AndroidManifest.xml
:
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

Add to
Info.plist
:
xml
<key>NSMicrophoneUsageDescription</key>
<string>$(PRODUCT_NAME) needs microphone access for calls</string>

添加到
Info.plist
:
xml
<key>NSMicrophoneUsageDescription</key>
<string>$(PRODUCT_NAME) needs microphone access for calls</string>

Authentication

身份验证

Option 1: Credential-Based Login

选项1: 基于凭证的登录

dart
final telnyxClient = TelnyxClient();

final credentialConfig = CredentialConfig(
  sipUser: 'your_sip_username',
  sipPassword: 'your_sip_password',
  sipCallerIDName: 'Display Name',
  sipCallerIDNumber: '+15551234567',
  notificationToken: fcmOrApnsToken,  // Optional: for push
  autoReconnect: true,
  debug: true,
  logLevel: LogLevel.debug,
);

telnyxClient.connectWithCredential(credentialConfig);
dart
final telnyxClient = TelnyxClient();

final credentialConfig = CredentialConfig(
  sipUser: 'your_sip_username',
  sipPassword: 'your_sip_password',
  sipCallerIDName: 'Display Name',
  sipCallerIDNumber: '+15551234567',
  notificationToken: fcmOrApnsToken,  // Optional: for push
  autoReconnect: true,
  debug: true,
  logLevel: LogLevel.debug,
);

telnyxClient.connectWithCredential(credentialConfig);

Option 2: Token-Based Login (JWT)

选项2: 基于Token的登录(JWT)

dart
final tokenConfig = TokenConfig(
  sipToken: 'your_jwt_token',
  sipCallerIDName: 'Display Name',
  sipCallerIDNumber: '+15551234567',
  notificationToken: fcmOrApnsToken,
  autoReconnect: true,
  debug: true,
);

telnyxClient.connectWithToken(tokenConfig);
dart
final tokenConfig = TokenConfig(
  sipToken: 'your_jwt_token',
  sipCallerIDName: 'Display Name',
  sipCallerIDNumber: '+15551234567',
  notificationToken: fcmOrApnsToken,
  autoReconnect: true,
  debug: true,
);

telnyxClient.connectWithToken(tokenConfig);

Configuration Options

配置选项

ParameterTypeDescription
sipUser
/
sipToken
StringCredentials from Telnyx Portal
sipCallerIDName
StringCaller ID name displayed to recipients
sipCallerIDNumber
StringCaller ID number
notificationToken
String?FCM (Android) or APNS (iOS) token
autoReconnect
boolAuto-retry login on failure
debug
boolEnable call quality metrics
logLevel
LogLevelnone, error, warning, debug, info, all
ringTonePath
String?Custom ringtone asset path
ringbackPath
String?Custom ringback tone asset path

参数类型描述
sipUser
/
sipToken
String从Telnyx门户获取的凭证
sipCallerIDName
String展示给接收方的来电显示名称
sipCallerIDNumber
String来电显示号码
notificationToken
String?FCM (Android) 或 APNS (iOS) 令牌
autoReconnect
bool登录失败时自动重试
debug
bool启用通话质量指标统计
logLevel
LogLevel可选值: none, error, warning, debug, info, all
ringTonePath
String?自定义铃声资源路径
ringbackPath
String?自定义回铃音资源路径

Making Outbound Calls

拨打外呼

dart
telnyxClient.call.newInvite(
  'John Doe',           // callerName
  '+15551234567',       // callerNumber
  '+15559876543',       // destinationNumber
  'my-custom-state',    // clientState
);

dart
telnyxClient.call.newInvite(
  'John Doe',           // callerName
  '+15551234567',       // callerNumber
  '+15559876543',       // destinationNumber
  'my-custom-state',    // clientState
);

Receiving Inbound Calls

接听来电

Listen for socket events:
dart
InviteParams? _incomingInvite;
Call? _currentCall;

telnyxClient.onSocketMessageReceived = (TelnyxMessage message) {
  switch (message.socketMethod) {
    case SocketMethod.CLIENT_READY:
      // Ready to make/receive calls
      break;
      
    case SocketMethod.LOGIN:
      // Successfully logged in
      break;
      
    case SocketMethod.INVITE:
      // Incoming call!
      _incomingInvite = message.message.inviteParams;
      // Show incoming call UI...
      break;
      
    case SocketMethod.ANSWER:
      // Call was answered
      break;
      
    case SocketMethod.BYE:
      // Call ended
      break;
  }
};

// Accept the incoming call
void acceptCall() {
  if (_incomingInvite != null) {
    _currentCall = telnyxClient.acceptCall(
      _incomingInvite!,
      'My Name',
      '+15551234567',
      'state',
    );
  }
}

监听Socket事件:
dart
InviteParams? _incomingInvite;
Call? _currentCall;

telnyxClient.onSocketMessageReceived = (TelnyxMessage message) {
  switch (message.socketMethod) {
    case SocketMethod.CLIENT_READY:
      // 已准备好拨打/接听通话
      break;
      
    case SocketMethod.LOGIN:
      // 登录成功
      break;
      
    case SocketMethod.INVITE:
      // 有来电!
      _incomingInvite = message.message.inviteParams;
      // 展示来电界面...
      break;
      
    case SocketMethod.ANSWER:
      // 通话已被接听
      break;
      
    case SocketMethod.BYE:
      // 通话已结束
      break;
  }
};

// 接听来电
void acceptCall() {
  if (_incomingInvite != null) {
    _currentCall = telnyxClient.acceptCall(
      _incomingInvite!,
      'My Name',
      '+15551234567',
      'state',
    );
  }
}

Call Controls

通话控制

dart
// End call
telnyxClient.call.endCall(telnyxClient.call.callId);

// Decline incoming call
telnyxClient.createCall().endCall(_incomingInvite?.callID);

// Mute/Unmute
telnyxClient.call.onMuteUnmutePressed();

// Hold/Unhold
telnyxClient.call.onHoldUnholdPressed();

// Toggle speaker
telnyxClient.call.enableSpeakerPhone(true);

// Send DTMF tone
telnyxClient.call.dtmf(telnyxClient.call.callId, '1');

dart
// 结束通话
telnyxClient.call.endCall(telnyxClient.call.callId);

// 拒接来电
telnyxClient.createCall().endCall(_incomingInvite?.callID);

// 静音/取消静音
telnyxClient.call.onMuteUnmutePressed();

// 保持/取消保持
telnyxClient.call.onHoldUnholdPressed();

// 切换扬声器
telnyxClient.call.enableSpeakerPhone(true);

// 发送DTMF音
telnyxClient.call.dtmf(telnyxClient.call.callId, '1');

Push Notifications - Android (FCM)

推送通知 - Android (FCM)

1. Setup Firebase

1. 配置Firebase

dart
// main.dart
('vm:entry-point')
Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  if (defaultTargetPlatform == TargetPlatform.android) {
    await Firebase.initializeApp();
    FirebaseMessaging.onBackgroundMessage(_firebaseBackgroundHandler);
  }
  
  runApp(const MyApp());
}
dart
// main.dart
('vm:entry-point')
Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  if (defaultTargetPlatform == TargetPlatform.android) {
    await Firebase.initializeApp();
    FirebaseMessaging.onBackgroundMessage(_firebaseBackgroundHandler);
  }
  
  runApp(const MyApp());
}

2. Background Handler

2. 后台处理器

dart
Future<void> _firebaseBackgroundHandler(RemoteMessage message) async {
  // Show notification (e.g., using flutter_callkit_incoming)
  showIncomingCallNotification(message);
  
  // Listen for user action
  FlutterCallkitIncoming.onEvent.listen((CallEvent? event) {
    switch (event!.event) {
      case Event.actionCallAccept:
        TelnyxClient.setPushMetaData(
          message.data,
          isAnswer: true,
          isDecline: false,
        );
        break;
      case Event.actionCallDecline:
        TelnyxClient.setPushMetaData(
          message.data,
          isAnswer: false,
          isDecline: true,  // SDK handles decline automatically
        );
        break;
    }
  });
}
dart
Future<void> _firebaseBackgroundHandler(RemoteMessage message) async {
  // 展示通知(例如使用flutter_callkit_incoming)
  showIncomingCallNotification(message);
  
  // 监听用户操作
  FlutterCallkitIncoming.onEvent.listen((CallEvent? event) {
    switch (event!.event) {
      case Event.actionCallAccept:
        TelnyxClient.setPushMetaData(
          message.data,
          isAnswer: true,
          isDecline: false,
        );
        break;
      case Event.actionCallDecline:
        TelnyxClient.setPushMetaData(
          message.data,
          isAnswer: false,
          isDecline: true,  // SDK自动处理拒接逻辑
        );
        break;
    }
  });
}

3. Handle Push When App Opens

3. 应用打开时处理推送

dart
Future<void> _handlePushNotification() async {
  final data = await TelnyxClient.getPushMetaData();
  if (data != null) {
    PushMetaData pushMetaData = PushMetaData.fromJson(data);
    telnyxClient.handlePushNotification(
      pushMetaData,
      credentialConfig,
      tokenConfig,
    );
  }
}
dart
Future<void> _handlePushNotification() async {
  final data = await TelnyxClient.getPushMetaData();
  if (data != null) {
    PushMetaData pushMetaData = PushMetaData.fromJson(data);
    telnyxClient.handlePushNotification(
      pushMetaData,
      credentialConfig,
      tokenConfig,
    );
  }
}

Early Accept/Decline Handling

提前接听/拒接处理

dart
bool _waitingForInvite = false;

void acceptCall() {
  if (_incomingInvite != null) {
    _currentCall = telnyxClient.acceptCall(...);
  } else {
    // Set flag if invite hasn't arrived yet
    _waitingForInvite = true;
  }
}

// In socket message handler:
case SocketMethod.INVITE:
  _incomingInvite = message.message.inviteParams;
  if (_waitingForInvite) {
    acceptCall();  // Accept now that invite arrived
    _waitingForInvite = false;
  }
  break;

dart
bool _waitingForInvite = false;

void acceptCall() {
  if (_incomingInvite != null) {
    _currentCall = telnyxClient.acceptCall(...);
  } else {
    // 如果邀请还未到达则设置标记
    _waitingForInvite = true;
  }
}

// 在Socket消息处理器中:
case SocketMethod.INVITE:
  _incomingInvite = message.message.inviteParams;
  if (_waitingForInvite) {
    acceptCall();  // 邀请到达后自动接听
    _waitingForInvite = false;
  }
  break;

Push Notifications - iOS (APNS + PushKit)

推送通知 - iOS (APNS + PushKit)

1. AppDelegate Setup

1. AppDelegate配置

swift
// AppDelegate.swift
func pushRegistry(_ registry: PKPushRegistry, 
                  didUpdate credentials: PKPushCredentials, 
                  for type: PKPushType) {
    let deviceToken = credentials.token.map { 
        String(format: "%02x", $0) 
    }.joined()
    SwiftFlutterCallkitIncomingPlugin.sharedInstance?
        .setDevicePushTokenVoIP(deviceToken)
}

func pushRegistry(_ registry: PKPushRegistry,
                  didReceiveIncomingPushWith payload: PKPushPayload,
                  for type: PKPushType,
                  completion: @escaping () -> Void) {
    guard type == .voIP else { return }
    
    if let metadata = payload.dictionaryPayload["metadata"] as? [String: Any] {
        let callerName = (metadata["caller_name"] as? String) ?? ""
        let callerNumber = (metadata["caller_number"] as? String) ?? ""
        let callId = (metadata["call_id"] as? String) ?? UUID().uuidString
        
        let data = flutter_callkit_incoming.Data(
            id: callId,
            nameCaller: callerName,
            handle: callerNumber,
            type: 0
        )
        data.extra = payload.dictionaryPayload as NSDictionary
        
        SwiftFlutterCallkitIncomingPlugin.sharedInstance?
            .showCallkitIncoming(data, fromPushKit: true)
    }
}
swift
// AppDelegate.swift
func pushRegistry(_ registry: PKPushRegistry, 
                  didUpdate credentials: PKPushCredentials, 
                  for type: PKPushType) {
    let deviceToken = credentials.token.map { 
        String(format: "%02x", $0) 
    }.joined()
    SwiftFlutterCallkitIncomingPlugin.sharedInstance?
        .setDevicePushTokenVoIP(deviceToken)
}

func pushRegistry(_ registry: PKPushRegistry,
                  didReceiveIncomingPushWith payload: PKPushPayload,
                  for type: PKPushType,
                  completion: @escaping () -> Void) {
    guard type == .voIP else { return }
    
    if let metadata = payload.dictionaryPayload["metadata"] as? [String: Any] {
        let callerName = (metadata["caller_name"] as? String) ?? ""
        let callerNumber = (metadata["caller_number"] as? String) ?? ""
        let callId = (metadata["call_id"] as? String) ?? UUID().uuidString
        
        let data = flutter_callkit_incoming.Data(
            id: callId,
            nameCaller: callerName,
            handle: callerNumber,
            type: 0
        )
        data.extra = payload.dictionaryPayload as NSDictionary
        
        SwiftFlutterCallkitIncomingPlugin.sharedInstance?
            .showCallkitIncoming(data, fromPushKit: true)
    }
}

2. Handle in Flutter

2. 在Flutter中处理

dart
FlutterCallkitIncoming.onEvent.listen((CallEvent? event) {
  switch (event!.event) {
    case Event.actionCallIncoming:
      PushMetaData? pushMetaData = PushMetaData.fromJson(
        event.body['extra']['metadata']
      );
      telnyxClient.handlePushNotification(
        pushMetaData,
        credentialConfig,
        tokenConfig,
      );
      break;
    case Event.actionCallAccept:
      // Handle accept
      break;
  }
});

dart
FlutterCallkitIncoming.onEvent.listen((CallEvent? event) {
  switch (event!.event) {
    case Event.actionCallIncoming:
      PushMetaData? pushMetaData = PushMetaData.fromJson(
        event.body['extra']['metadata']
      );
      telnyxClient.handlePushNotification(
        pushMetaData,
        credentialConfig,
        tokenConfig,
      );
      break;
    case Event.actionCallAccept:
      // 处理接听逻辑
      break;
  }
});

Handling Late Notifications

延迟通知处理

dart
const CALL_MISSED_TIMEOUT = 60;  // seconds

void handlePushMessage(RemoteMessage message) {
  DateTime now = DateTime.now();
  Duration? diff = now.difference(message.sentTime!);
  
  if (diff.inSeconds > CALL_MISSED_TIMEOUT) {
    showMissedCallNotification(message);
    return;
  }
  
  // Handle normal incoming call...
}

dart
const CALL_MISSED_TIMEOUT = 60;  // 单位: 秒

void handlePushMessage(RemoteMessage message) {
  DateTime now = DateTime.now();
  Duration? diff = now.difference(message.sentTime!);
  
  if (diff.inSeconds > CALL_MISSED_TIMEOUT) {
    showMissedCallNotification(message);
    return;
  }
  
  // 处理正常来电...
}

Call Quality Metrics

通话质量指标

Enable with
debug: true
in config:
dart
// When making a call
call.newInvite(
  callerName: 'John',
  callerNumber: '+15551234567',
  destinationNumber: '+15559876543',
  clientState: 'state',
  debug: true,
);

// Listen for quality updates
call.onCallQualityChange = (CallQualityMetrics metrics) {
  print('MOS: ${metrics.mos}');
  print('Jitter: ${metrics.jitter * 1000} ms');
  print('RTT: ${metrics.rtt * 1000} ms');
  print('Quality: ${metrics.quality}');  // excellent, good, fair, poor, bad
};
Quality LevelMOS Range
excellent> 4.2
good4.1 - 4.2
fair3.7 - 4.0
poor3.1 - 3.6
bad≤ 3.0

在配置中开启
debug: true
即可启用:
dart
// 拨打通话时
call.newInvite(
  callerName: 'John',
  callerNumber: '+15551234567',
  destinationNumber: '+15559876543',
  clientState: 'state',
  debug: true,
);

// 监听质量更新
call.onCallQualityChange = (CallQualityMetrics metrics) {
  print('MOS: ${metrics.mos}');
  print('Jitter: ${metrics.jitter * 1000} ms');
  print('RTT: ${metrics.rtt * 1000} ms');
  print('Quality: ${metrics.quality}');  // 可选值: excellent, good, fair, poor, bad
};
质量等级MOS值范围
excellent> 4.2
good4.1 - 4.2
fair3.7 - 4.0
poor3.1 - 3.6
bad≤ 3.0

AI Agent Integration

AI Agent集成

Connect to a Telnyx Voice AI Agent:
连接到Telnyx语音AI Agent:

1. Anonymous Login

1. 匿名登录

dart
try {
  await telnyxClient.anonymousLogin(
    targetId: 'your_ai_assistant_id',
    targetType: 'ai_assistant',  // Default
    targetVersionId: 'optional_version_id',  // Optional
  );
} catch (e) {
  print('Login failed: $e');
}
dart
try {
  await telnyxClient.anonymousLogin(
    targetId: 'your_ai_assistant_id',
    targetType: 'ai_assistant',  // 默认值
    targetVersionId: 'optional_version_id',  // 可选
  );
} catch (e) {
  print('Login failed: $e');
}

2. Start Conversation

2. 开启对话

dart
telnyxClient.newInvite(
  'User Name',
  '+15551234567',
  '',  // Destination ignored for AI Agent
  'state',
  customHeaders: {
    'X-Account-Number': '123',  // Maps to {{account_number}}
    'X-User-Tier': 'premium',   // Maps to {{user_tier}}
  },
);
dart
telnyxClient.newInvite(
  'User Name',
  '+15551234567',
  '',  // AI Agent场景下忽略目标号码
  'state',
  customHeaders: {
    'X-Account-Number': '123',  // 映射到 {{account_number}}
    'X-User-Tier': 'premium',   // 映射到 {{user_tier}}
  },
);

3. Receive Transcripts

3. 接收对话转录

dart
telnyxClient.onTranscriptUpdate = (List<TranscriptItem> transcript) {
  for (var item in transcript) {
    print('${item.role}: ${item.content}');
    // role: 'user' or 'assistant'
    // content: transcribed text
    // timestamp: when received
  }
};

// Get current transcript anytime
List<TranscriptItem> current = telnyxClient.transcript;

// Clear transcript
telnyxClient.clearTranscript();
dart
telnyxClient.onTranscriptUpdate = (List<TranscriptItem> transcript) {
  for (var item in transcript) {
    print('${item.role}: ${item.content}');
    // role: 'user' 或 'assistant'
    // content: 转录的文本内容
    // timestamp: 接收时间
  }
};

// 随时获取当前转录内容
List<TranscriptItem> current = telnyxClient.transcript;

// 清空转录内容
telnyxClient.clearTranscript();

4. Send Text to AI Agent

4. 向AI Agent发送文本

dart
Call? activeCall = telnyxClient.calls.values.firstOrNull;

if (activeCall != null) {
  activeCall.sendConversationMessage(
    'Hello, I need help with my account'
  );
}

dart
Call? activeCall = telnyxClient.calls.values.firstOrNull;

if (activeCall != null) {
  activeCall.sendConversationMessage(
    'Hello, I need help with my account'
  );
}

Custom Logging

自定义日志

dart
class MyCustomLogger extends CustomLogger {
  
  log(LogLevel level, String message) {
    print('[$level] $message');
    // Send to analytics, file, server, etc.
  }
}

final config = CredentialConfig(
  // ... other config
  logLevel: LogLevel.debug,
  customLogger: MyCustomLogger(),
);

dart
class MyCustomLogger extends CustomLogger {
  
  log(LogLevel level, String message) {
    print('[$level] $message');
    // 可发送到分析平台、文件、服务器等
  }
}

final config = CredentialConfig(
  // ... 其他配置
  logLevel: LogLevel.debug,
  customLogger: MyCustomLogger(),
);

Troubleshooting

故障排查

IssueSolution
No audio on AndroidCheck RECORD_AUDIO permission
No audio on iOSCheck NSMicrophoneUsageDescription in Info.plist
Push not working (debug)Push only works in release mode
Login failsVerify SIP credentials in Telnyx Portal
10-second timeoutINVITE didn't arrive - check network/push setup
sender_id_mismatchFCM project mismatch between app and server
<!-- BEGIN AUTO-GENERATED API REFERENCE -- do not edit below this line -->
references/webrtc-server-api.md has the server-side WebRTC API — credential creation, token generation, and push notification setup. You MUST read it when setting up authentication or push notifications.
问题解决方案
Android端无音频检查RECORD_AUDIO权限
iOS端无音频检查Info.plist中的NSMicrophoneUsageDescription配置
调试模式下推送不工作推送仅在发布模式下生效
登录失败验证Telnyx门户中的SIP凭证是否正确
10秒超时INVITE请求未到达 - 检查网络/推送配置
sender_id_mismatch应用和服务端使用的FCM项目不匹配
<!-- BEGIN AUTO-GENERATED API REFERENCE -- do not edit below this line -->
references/webrtc-server-api.md包含服务端WebRTC API相关内容——凭证创建、令牌生成和推送通知配置。在配置身份验证或推送通知时必须阅读该文档。

API Reference

API参考

TxClient

TxClient

Telnyx Client

Telnyx客户端

TelnyxClient() is the core class of the SDK, and can be used to connect to our backend socket connection, create calls, check state and disconnect, etc.
dart
    TelnyxClient _telnyxClient = TelnyxClient();
TelnyxClient()是该SDK的核心类,可用于连接后端Socket连接、创建通话、检查状态和断开连接等。
dart
    TelnyxClient _telnyxClient = TelnyxClient();

Logging into Telnyx Client

登录Telnyx客户端

To log into the Telnyx WebRTC client, you'll need to authenticate using a Telnyx SIP Connection. Follow our quickstart guide to create JWTs (JSON Web Tokens) to authenticate. To log in with a token we use the connectWithToken() method. You can also authenticate directly with the SIP Connection
username
and
password
with the connectWithCredential() method:
dart
    _telnyxClient.connectWithToken(tokenConfig)
                     //OR
    _telnyxClient.connectWithCredential(credentialConfig)             
要登录Telnyx WebRTC客户端,你需要使用Telnyx SIP连接进行身份验证。按照我们的快速入门指南创建JWT(JSON Web Tokens)完成身份验证。使用connectWithToken()方法可以通过token登录,你也可以使用connectWithCredential()方法通过SIP连接的
username
password
直接进行身份验证:
dart
    _telnyxClient.connectWithToken(tokenConfig)
                     // 或
    _telnyxClient.connectWithCredential(credentialConfig)             

Listening for events and reacting - Accepting a Call

监听事件并响应 - 接听通话

In order to be able to accept a call, we first need to listen for invitations. We do this by getting the Telnyx Socket Response callbacks from our TelnyxClient:
为了能够接听通话,我们首先需要监听来电邀请。我们可以通过TelnyxClient获取Telnyx Socket响应回调来实现这一点:

Call

Call

Call

通话对象

The Call class is used to manage the call state and call actions. It is used to accept, decline, end, mute, hold, and send DTMF tones during a call.
Call类用于管理通话状态和通话操作,可用于在通话过程中执行接听、拒接、结束、静音、保持和发送DTMF音等操作。

Accept Call

接听通话

In order to accept a call, we simply retrieve the instance of the call and use the .acceptCall(callID) method:
dart
    _telnyxClient.call.acceptCall(_incomingInvite?.callID);
要接听通话,只需获取通话实例并调用.acceptCall(callID)方法:
dart
    _telnyxClient.call.acceptCall(_incomingInvite?.callID);

Decline / End Call

拒接 / 结束通话

In order to end a call, we can get a stored instance of Call and call the .endCall(callID) method. To decline an incoming call we first create the call with the .createCall() method and then call the .endCall(callID) method:
dart
    if (_ongoingCall) {
      _telnyxClient.call.endCall(_telnyxClient.call.callId);
    } else {
      _telnyxClient.createCall().endCall(_incomingInvite?.callID);
    }
要结束通话,可以获取已存储的Call实例并调用.endCall(callID)方法。要拒接来电,首先使用.createCall()方法创建通话对象,然后调用.endCall(callID)方法:
dart
    if (_ongoingCall) {
      _telnyxClient.call.endCall(_telnyxClient.call.callId);
    } else {
      _telnyxClient.createCall().endCall(_incomingInvite?.callID);
    }

DTMF (Dual Tone Multi Frequency)

DTMF (双音多频)

In order to send a DTMF message while on a call you can call the .dtmf(callID, tone), method where tone is a String value of the character you would like pressed:
dart
    _telnyxClient.call.dtmf(_telnyxClient.call.callId, tone);
要在通话过程中发送DTMF消息,可以调用.dtmf(callID, tone)方法,其中tone是你想要按下的字符对应的字符串值:
dart
    _telnyxClient.call.dtmf(_telnyxClient.call.callId, tone);

Mute a call

通话静音

To mute a call, you can simply call the .onMuteUnmutePressed() method:
dart
    _telnyxClient.call.onMuteUnmutePressed();
要将通话静音,只需调用.onMuteUnmutePressed()方法:
dart
    _telnyxClient.call.onMuteUnmutePressed();

Toggle loud speaker

切换扬声器

To toggle loud speaker, you can simply call .enableSpeakerPhone(bool):
dart
    _telnyxClient.call.enableSpeakerPhone(true);
要切换扬声器状态,只需调用.enableSpeakerPhone(bool)方法:
dart
    _telnyxClient.call.enableSpeakerPhone(true);

Put a call on hold

通话保持

To put a call on hold, you can simply call the .onHoldUnholdPressed() method:
dart
    _telnyxClient.call.onHoldUnholdPressed();
<!-- END AUTO-GENERATED API REFERENCE -->
要将通话保持,只需调用.onHoldUnholdPressed()方法:
dart
    _telnyxClient.call.onHoldUnholdPressed();
<!-- END AUTO-GENERATED API REFERENCE -->