telnyx-webrtc-client-android
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTelnyx WebRTC - Android SDK
Telnyx WebRTC - Android SDK
Build real-time voice communication into Android applications using Telnyx WebRTC.
Prerequisites: Create WebRTC credentials and generate a login token using the Telnyx server-side SDK. See theskill in your server language plugin (e.g.,telnyx-webrtc-*,telnyx-python).telnyx-javascript
使用Telnyx WebRTC为Android应用集成实时语音通信能力。
前置条件: 创建WebRTC凭证,并使用Telnyx服务端SDK生成登录令牌。可参考对应服务端语言插件中的技能(例如telnyx-webrtc-*、telnyx-python)。telnyx-javascript
Installation
安装
Add JitPack repository to your project's :
build.gradlegradle
allprojects {
repositories {
maven { url 'https://jitpack.io' }
}
}Add the dependency:
gradle
dependencies {
implementation 'com.github.team-telnyx:telnyx-webrtc-android:latest-version'
}将JitPack仓库添加到项目的文件中:
build.gradlegradle
allprojects {
repositories {
maven { url 'https://jitpack.io' }
}
}添加依赖:
gradle
dependencies {
implementation 'com.github.team-telnyx:telnyx-webrtc-android:latest-version'
}Required Permissions
所需权限
Add to :
AndroidManifest.xmlxml
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- For push notifications (Android 14+) -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_PHONE_CALL"/>添加到文件中:
AndroidManifest.xmlxml
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 推送通知所需权限(Android 14及以上) -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_PHONE_CALL"/>Authentication
身份验证
Option 1: Credential-Based Login
方案1:基于凭证的登录
kotlin
val telnyxClient = TelnyxClient(context)
telnyxClient.connect()
val credentialConfig = CredentialConfig(
sipUser = "your_sip_username",
sipPassword = "your_sip_password",
sipCallerIDName = "Display Name",
sipCallerIDNumber = "+15551234567",
fcmToken = fcmToken, // Optional: for push notifications
logLevel = LogLevel.DEBUG,
autoReconnect = true
)
telnyxClient.credentialLogin(credentialConfig)kotlin
val telnyxClient = TelnyxClient(context)
telnyxClient.connect()
val credentialConfig = CredentialConfig(
sipUser = "your_sip_username",
sipPassword = "your_sip_password",
sipCallerIDName = "Display Name",
sipCallerIDNumber = "+15551234567",
fcmToken = fcmToken, // 可选:用于推送通知
logLevel = LogLevel.DEBUG,
autoReconnect = true
)
telnyxClient.credentialLogin(credentialConfig)Option 2: Token-Based Login (JWT)
方案2:基于令牌的登录(JWT)
kotlin
val tokenConfig = TokenConfig(
sipToken = "your_jwt_token",
sipCallerIDName = "Display Name",
sipCallerIDNumber = "+15551234567",
fcmToken = fcmToken,
logLevel = LogLevel.DEBUG,
autoReconnect = true
)
telnyxClient.tokenLogin(tokenConfig)kotlin
val tokenConfig = TokenConfig(
sipToken = "your_jwt_token",
sipCallerIDName = "Display Name",
sipCallerIDNumber = "+15551234567",
fcmToken = fcmToken,
logLevel = LogLevel.DEBUG,
autoReconnect = true
)
telnyxClient.tokenLogin(tokenConfig)Configuration Options
配置选项
| Parameter | Type | Description |
|---|---|---|
| String | Credentials from Telnyx Portal |
| String? | Caller ID name displayed to recipients |
| String? | Caller ID number |
| String? | Firebase Cloud Messaging token for push |
| Any? | Raw resource ID or URI for ringtone |
| Int? | Raw resource ID for ringback tone |
| LogLevel | NONE, ERROR, WARNING, DEBUG, INFO, ALL |
| Boolean | Auto-retry login on failure (3 attempts) |
| Region | AUTO, US_EAST, US_WEST, EU_WEST |
| 参数 | 类型 | 描述 |
|---|---|---|
| String | 来自Telnyx门户的凭证 |
| String? | 向接收方展示的来电显示名称 |
| String? | 来电显示号码 |
| String? | 用于推送的Firebase Cloud Messaging令牌 |
| Any? | 铃声的原生资源ID或URI |
| Int? | 回铃音的原生资源ID |
| LogLevel | NONE, ERROR, WARNING, DEBUG, INFO, ALL |
| Boolean | 登录失败时自动重试(最多3次) |
| Region | AUTO, US_EAST, US_WEST, EU_WEST |
Making Outbound Calls
拨打外呼电话
kotlin
// Create a new outbound call
telnyxClient.call.newInvite(
callerName = "John Doe",
callerNumber = "+15551234567",
destinationNumber = "+15559876543",
clientState = "my-custom-state"
)kotlin
// 创建新的外呼通话
telnyxClient.call.newInvite(
callerName = "John Doe",
callerNumber = "+15551234567",
destinationNumber = "+15559876543",
clientState = "my-custom-state"
)Receiving Inbound Calls
接听来电
Listen for socket events using SharedFlow (recommended):
kotlin
lifecycleScope.launch {
telnyxClient.socketResponseFlow.collect { response ->
when (response.status) {
SocketStatus.ESTABLISHED -> {
// Socket connected
}
SocketStatus.MESSAGERECEIVED -> {
response.data?.let { data ->
when (data.method) {
SocketMethod.CLIENT_READY.methodName -> {
// Ready to make/receive calls
}
SocketMethod.LOGIN.methodName -> {
// Successfully logged in
}
SocketMethod.INVITE.methodName -> {
// Incoming call!
val invite = data.result as InviteResponse
// Show incoming call UI, then accept:
telnyxClient.acceptCall(
invite.callId,
invite.callerIdNumber
)
}
SocketMethod.ANSWER.methodName -> {
// Call was answered
}
SocketMethod.BYE.methodName -> {
// Call ended
}
SocketMethod.RINGING.methodName -> {
// Remote party is ringing
}
}
}
}
SocketStatus.ERROR -> {
// Handle error: response.errorCode
}
SocketStatus.DISCONNECT -> {
// Socket disconnected
}
}
}
}使用SharedFlow监听Socket事件(推荐方案):
kotlin
lifecycleScope.launch {
telnyxClient.socketResponseFlow.collect { response ->
when (response.status) {
SocketStatus.ESTABLISHED -> {
// Socket已连接
}
SocketStatus.MESSAGERECEIVED -> {
response.data?.let { data ->
when (data.method) {
SocketMethod.CLIENT_READY.methodName -> {
// 已准备好拨打/接听电话
}
SocketMethod.LOGIN.methodName -> {
// 登录成功
}
SocketMethod.INVITE.methodName -> {
// 收到来电!
val invite = data.result as InviteResponse
// 展示来电界面,然后接听:
telnyxClient.acceptCall(
invite.callId,
invite.callerIdNumber
)
}
SocketMethod.ANSWER.methodName -> {
// 通话已被接听
}
SocketMethod.BYE.methodName -> {
// 通话已结束
}
SocketMethod.RINGING.methodName -> {
// 对方正在响铃
}
}
}
}
SocketStatus.ERROR -> {
// 处理错误:response.errorCode
}
SocketStatus.DISCONNECT -> {
// Socket已断开连接
}
}
}
}Call Controls
通话控制
kotlin
// Get current call
val currentCall: Call? = telnyxClient.calls[callId]
// End call
currentCall?.endCall(callId)
// Mute/Unmute
currentCall?.onMuteUnmutePressed()
// Hold/Unhold
currentCall?.onHoldUnholdPressed(callId)
// Send DTMF tone
currentCall?.dtmf(callId, "1")kotlin
// 获取当前通话
val currentCall: Call? = telnyxClient.calls[callId]
// 结束通话
currentCall?.endCall(callId)
// 静音/取消静音
currentCall?.onMuteUnmutePressed()
// 保持/取消保持
currentCall?.onHoldUnholdPressed(callId)
// 发送DTMF音
currentCall?.dtmf(callId, "1")Handling Multiple Calls
处理多路通话
kotlin
// Get all active calls
val calls: Map<UUID, Call> = telnyxClient.calls
// Iterate through calls
calls.forEach { (callId, call) ->
// Handle each call
}kotlin
// 获取所有活跃通话
val calls: Map<UUID, Call> = telnyxClient.calls
// 遍历所有通话
calls.forEach { (callId, call) ->
// 处理每一路通话
}Push Notifications (FCM)
推送通知(FCM)
1. Setup Firebase
1. 配置Firebase
Add Firebase to your project and get an FCM token:
kotlin
FirebaseMessaging.getInstance().token.addOnCompleteListener { task ->
if (task.isSuccessful) {
val fcmToken = task.result
// Use this token in your login config
}
}将Firebase添加到你的项目中并获取FCM令牌:
kotlin
FirebaseMessaging.getInstance().token.addOnCompleteListener { task ->
if (task.isSuccessful) {
val fcmToken = task.result
// 在登录配置中使用该令牌
}
}2. Handle Incoming Push
2. 处理收到的推送
In your :
FirebaseMessagingServicekotlin
class MyFirebaseService : FirebaseMessagingService() {
override fun onMessageReceived(remoteMessage: RemoteMessage) {
val params = remoteMessage.data
val metadata = JSONObject(params as Map<*, *>).getString("metadata")
// Check for missed call
if (params["message"] == "Missed call!") {
// Show missed call notification
return
}
// Show incoming call notification (use Foreground Service)
showIncomingCallNotification(metadata)
}
}在你的中:
FirebaseMessagingServicekotlin
class MyFirebaseService : FirebaseMessagingService() {
override fun onMessageReceived(remoteMessage: RemoteMessage) {
val params = remoteMessage.data
val metadata = JSONObject(params as Map<*, *>).getString("metadata")
// 检查是否为未接来电
if (params["message"] == "Missed call!") {
// 展示未接来电通知
return
}
// 展示来电通知(使用前台服务)
showIncomingCallNotification(metadata)
}
}3. Decline Push Call (Simplified)
3. 拒接推送来电(简化版)
kotlin
// The SDK now handles decline automatically
telnyxClient.connectWithDeclinePush(
txPushMetaData = pushMetaData,
credentialConfig = credentialConfig
)
// SDK connects, sends decline, and disconnects automaticallykotlin
// SDK现在会自动处理拒接逻辑
telnyxClient.connectWithDeclinePush(
txPushMetaData = pushMetaData,
credentialConfig = credentialConfig
)
// SDK会自动连接、发送拒接信号并断开连接Android 14+ Requirements
Android 14及以上版本要求
xml
<service
android:name=".YourForegroundService"
android:foregroundServiceType="phoneCall"
android:exported="true" />xml
<service
android:name=".YourForegroundService"
android:foregroundServiceType="phoneCall"
android:exported="true" />Call Quality Metrics
通话质量指标
Enable metrics to monitor call quality in real-time:
kotlin
val credentialConfig = CredentialConfig(
// ... other config
debug = true // Enables call quality metrics
)
// Listen for quality updates
lifecycleScope.launch {
currentCall?.callQualityFlow?.collect { metrics ->
println("MOS: ${metrics.mos}")
println("Jitter: ${metrics.jitter * 1000} ms")
println("RTT: ${metrics.rtt * 1000} ms")
println("Quality: ${metrics.quality}") // EXCELLENT, GOOD, FAIR, POOR, BAD
}
}| Quality Level | MOS Range |
|---|---|
| EXCELLENT | > 4.2 |
| GOOD | 4.1 - 4.2 |
| FAIR | 3.7 - 4.0 |
| POOR | 3.1 - 3.6 |
| BAD | ≤ 3.0 |
启用指标以实时监控通话质量:
kotlin
val credentialConfig = CredentialConfig(
// ... 其他配置
debug = true // 启用通话质量指标
)
// 监听质量更新
lifecycleScope.launch {
currentCall?.callQualityFlow?.collect { metrics ->
println("MOS: ${metrics.mos}")
println("Jitter: ${metrics.jitter * 1000} ms")
println("RTT: ${metrics.rtt * 1000} ms")
println("Quality: ${metrics.quality}") // EXCELLENT, GOOD, FAIR, POOR, BAD
}
}| 质量等级 | MOS范围 |
|---|---|
| EXCELLENT | > 4.2 |
| GOOD | 4.1 - 4.2 |
| FAIR | 3.7 - 4.0 |
| POOR | 3.1 - 3.6 |
| BAD | ≤ 3.0 |
AI Agent Integration
AI Agent集成
Connect to a Telnyx Voice AI Agent without traditional SIP credentials:
无需传统SIP凭证即可连接到Telnyx语音AI Agent:
1. Anonymous Login
1. 匿名登录
kotlin
telnyxClient.connectAnonymously(
targetId = "your_ai_assistant_id",
targetType = "ai_assistant", // Default
targetVersionId = "optional_version_id",
userVariables = mapOf("user_id" to "12345")
)kotlin
telnyxClient.connectAnonymously(
targetId = "your_ai_assistant_id",
targetType = "ai_assistant", // 默认值
targetVersionId = "optional_version_id",
userVariables = mapOf("user_id" to "12345")
)2. Start Conversation
2. 开启对话
kotlin
// After anonymous login, call the AI Agent
telnyxClient.newInvite(
callerName = "User Name",
callerNumber = "+15551234567",
destinationNumber = "", // Ignored for AI Agent
clientState = "state",
customHeaders = mapOf(
"X-Account-Number" to "123", // Maps to {{account_number}}
"X-User-Tier" to "premium" // Maps to {{user_tier}}
)
)kotlin
// 匿名登录后,呼叫AI Agent
telnyxClient.newInvite(
callerName = "User Name",
callerNumber = "+15551234567",
destinationNumber = "", // AI Agent场景下会忽略该字段
clientState = "state",
customHeaders = mapOf(
"X-Account-Number" to "123", // 映射到 {{account_number}}
"X-User-Tier" to "premium" // 映射到 {{user_tier}}
)
)3. Receive Transcripts
3. 接收通话转写
kotlin
lifecycleScope.launch {
telnyxClient.transcriptUpdateFlow.collect { transcript ->
transcript.forEach { item ->
println("${item.role}: ${item.content}")
// role: "user" or "assistant"
}
}
}kotlin
lifecycleScope.launch {
telnyxClient.transcriptUpdateFlow.collect { transcript ->
transcript.forEach { item ->
println("${item.role}: ${item.content}")
// role: "user" 或 "assistant"
}
}
}4. Send Text to AI Agent
4. 向AI Agent发送文本
kotlin
// Send text message during active call
telnyxClient.sendAIAssistantMessage("Hello, I need help with my account")kotlin
// 在活跃通话过程中发送文本消息
telnyxClient.sendAIAssistantMessage("Hello, I need help with my account")Custom Logging
自定义日志
Implement your own logger:
kotlin
class MyLogger : TxLogger {
override fun log(level: LogLevel, tag: String?, message: String, throwable: Throwable?) {
// Send to your logging service
MyAnalytics.log(level.name, tag ?: "Telnyx", message)
}
}
val config = CredentialConfig(
// ... other config
logLevel = LogLevel.ALL,
customLogger = MyLogger()
)实现你自己的日志记录器:
kotlin
class MyLogger : TxLogger {
override fun log(level: LogLevel, tag: String?, message: String, throwable: Throwable?) {
// 发送到你的日志服务
MyAnalytics.log(level.name, tag ?: "Telnyx", message)
}
}
val config = CredentialConfig(
// ... 其他配置
logLevel = LogLevel.ALL,
customLogger = MyLogger()
)ProGuard Rules
ProGuard规则
If using code obfuscation, add to :
proguard-rules.proproguard
-keep class com.telnyx.webrtc.** { *; }
-dontwarn kotlin.Experimental$Level
-dontwarn kotlin.Experimental
-dontwarn kotlinx.coroutines.scheduling.ExperimentalCoroutineDispatcher如果使用代码混淆,请将以下规则添加到中:
proguard-rules.proproguard
-keep class com.telnyx.webrtc.** { *; }
-dontwarn kotlin.Experimental$Level
-dontwarn kotlin.Experimental
-dontwarn kotlinx.coroutines.scheduling.ExperimentalCoroutineDispatcherTroubleshooting
问题排查
| Issue | Solution |
|---|---|
| No audio | Check RECORD_AUDIO permission is granted |
| Push not received | Verify FCM token is passed in config |
| Login fails | Verify SIP credentials in Telnyx Portal |
| Call drops | Check network stability, enable |
| sender_id_mismatch (push) | FCM project mismatch - ensure app's |
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.
| 问题 | 解决方案 |
|---|---|
| 没有声音 | 检查RECORD_AUDIO权限已被授予 |
| 收不到推送 | 验证配置中传入了正确的FCM令牌 |
| 登录失败 | 验证Telnyx门户中的SIP凭证是否正确 |
| 通话掉线 | 检查网络稳定性,开启 |
| sender_id_mismatch(推送相关) | FCM项目不匹配 —— 确保应用的 |
references/webrtc-server-api.md包含服务端WebRTC API相关内容 —— 凭证创建、令牌生成和推送通知配置。在设置身份验证或推送通知时你必须阅读该文档。
API Reference
API参考
TelnyxClient
TelnyxClient
TelnyxClientTelnyxClientCore Functionalities
核心功能
- Connection Management: Establishes and maintains a WebSocket connection to the Telnyx RTC platform.
- Authentication: Supports authentication via SIP credentials or tokens.
- Call Control: Provides methods to initiate (), accept (
newInvite), and end (acceptCall) calls.endCall - Event Handling: Uses to process events from the socket, such as incoming calls (
TxSocketListener), call answers (onOfferReceived), call termination (onAnswerReceived), and errors (onByeReceived).onErrorReceived - State Exposure: Exposes connection status, session information, and call events via (recommended:
SharedFlow) and deprecatedsocketResponseFlow(e.g.,LiveData) for UI consumption.socketResponseLiveData
- 连接管理:建立并维护与Telnyx RTC平台的WebSocket连接。
- 身份验证:支持通过SIP凭证或令牌进行身份验证。
- 通话控制:提供发起()、接听(
newInvite)和结束(acceptCall)通话的方法。endCall - 事件处理:使用处理来自Socket的事件,例如来电(
TxSocketListener)、通话被接听(onOfferReceived)、通话结束(onAnswerReceived)和错误(onByeReceived)。onErrorReceived - 状态暴露:通过(推荐使用
SharedFlow)和已废弃的socketResponseFlow(例如LiveData)暴露连接状态、会话信息和通话事件,供UI层消费。socketResponseLiveData
Key Components and Interactions
关键组件与交互逻辑
- : Manages the underlying WebSocket communication.
TxSocket - : An interface implemented by
TxSocketListenerto receive and process socket events. Notably:TelnyxClient- : Handles incoming call invitations.
onOfferReceived(jsonObject: JsonObject) - : Processes answers to outgoing calls.
onAnswerReceived(jsonObject: JsonObject) - : Handles call termination notifications. The
onByeReceived(jsonObject: JsonObject)now contains richer details includingjsonObject,cause,causeCode, andsipCode, allowing the client to populatesipReasonwith a detailedCallState.DONE.CallTerminationReason - : Manages errors reported by the socket or platform.
onErrorReceived(jsonObject: JsonObject) - : Indicates the client is ready for operations after connection and initial setup.
onClientReady(jsonObject: JsonObject) - : Provides updates on the registration status with the Telnyx gateway.
onGatewayStateReceived(gatewayState: String, receivedSessionId: String?)
- Class: Represents individual call sessions.
Callcreates and manages instances ofTelnyxClient.Call - : The client updates the
CallStateof individualCallStateobjects based on socket events and network conditions. This includes states likeCall,DROPPED(reason: CallNetworkChangeReason), andRECONNECTING(reason: CallNetworkChangeReason)which now provide more context.DONE(reason: CallTerminationReason?) - : This SharedFlow stream is the recommended approach for applications. It emits
socketResponseFlow: SharedFlow<SocketResponse<ReceivedMessageBody>>objects that wrap messages received from the Telnyx platform. ForSocketResponsemessages, theBYEwill contain aReceivedMessageBodywhich is now enriched with termination cause details.com.telnyx.webrtc.sdk.verto.receive.ByeResponse - : [DEPRECATED] This LiveData stream is deprecated in favor of
socketResponseLiveData: LiveData<SocketResponse<ReceivedMessageBody>>. It's maintained for backward compatibility but new implementations should use SharedFlow.socketResponseFlow
- :管理底层WebSocket通信。
TxSocket - :由
TxSocketListener实现的接口,用于接收和处理Socket事件。主要包括:TelnyxClient- :处理来电邀请。
onOfferReceived(jsonObject: JsonObject) - :处理外呼的接听响应。
onAnswerReceived(jsonObject: JsonObject) - :处理通话结束通知。现在
onByeReceived(jsonObject: JsonObject)包含更丰富的详情,包括jsonObject、cause、causeCode和sipCode,允许客户端为sipReason填充详细的CallState.DONE。CallTerminationReason - :处理Socket或平台上报的错误。
onErrorReceived(jsonObject: JsonObject) - :表示客户端在连接和初始设置完成后已准备好处理操作。
onClientReady(jsonObject: JsonObject) - :提供与Telnyx网关的注册状态更新。
onGatewayStateReceived(gatewayState: String, receivedSessionId: String?)
- 类:代表单个通话会话。
Call负责创建和管理TelnyxClient实例。Call - :客户端根据Socket事件和网络条件更新单个
CallState对象的Call。包含的状态有CallState、DROPPED(reason: CallNetworkChangeReason)和RECONNECTING(reason: CallNetworkChangeReason),现在这些状态都提供了更多上下文信息。DONE(reason: CallTerminationReason?) - :推荐应用使用的SharedFlow流。它会发送封装了从Telnyx平台收到的消息的
socketResponseFlow: SharedFlow<SocketResponse<ReceivedMessageBody>>对象。对于SocketResponse消息,BYE会包含ReceivedMessageBody,现在该对象已补充了通话结束原因的详细信息。com.telnyx.webrtc.sdk.verto.receive.ByeResponse - :[已废弃] 该LiveData流已被弃用,推荐使用
socketResponseLiveData: LiveData<SocketResponse<ReceivedMessageBody>>。它会被保留以保证向后兼容,但新的实现应该使用SharedFlow。socketResponseFlow
Usage Example
使用示例
Recommended approach using SharedFlow:
kotlin
// Initializing the client
val telnyxClient = TelnyxClient(context)
// Observing responses using SharedFlow (Recommended)
lifecycleScope.launch {
telnyxClient.socketResponseFlow.collect { response ->
when (response.status) {
SocketStatus.MESSAGERECEIVED -> {
response.data?.let {
when (it.method) {
SocketMethod.INVITE.methodName -> {
val invite = it.result as InviteResponse
// Handle incoming call invitation
}
SocketMethod.BYE.methodName -> {
val bye = it.result as com.telnyx.webrtc.sdk.verto.receive.ByeResponse
// Call ended by remote party, bye.cause, bye.sipCode etc. are available
Log.d("TelnyxClient", "Call ended: ${bye.callId}, Reason: ${bye.cause}")
}
// Handle other methods like ANSWER, RINGING, etc.
}
}
}
SocketStatus.ERROR -> {
// Handle errors
Log.e("TelnyxClient", "Error: ${response.errorMessage}")
}
// Handle other statuses: ESTABLISHED, LOADING, DISCONNECT
}
}
}Deprecated approach using LiveData:
kotlin
@Deprecated("Use socketResponseFlow instead. LiveData is deprecated in favor of Kotlin Flows.")
// Observing responses (including errors and BYE messages)
telnyxClient.socketResponseLiveData.observe(lifecycleOwner, Observer { response ->
when (response.status) {
SocketStatus.MESSAGERECEIVED -> {
response.data?.let {
when (it.method) {
SocketMethod.INVITE.methodName -> {
val invite = it.result as InviteResponse
// Handle incoming call invitation
}
SocketMethod.BYE.methodName -> {
val bye = it.result as com.telnyx.webrtc.sdk.verto.receive.ByeResponse
// Call ended by remote party, bye.cause, bye.sipCode etc. are available
Log.d("TelnyxClient", "Call ended: ${bye.callId}, Reason: ${bye.cause}")
}
// Handle other methods like ANSWER, RINGING, etc.
}
}
}
SocketStatus.ERROR -> {
// Handle errors
Log.e("TelnyxClient", "Error: ${response.errorMessage}")
}
// Handle other statuses: ESTABLISHED, LOADING, DISCONNECT
}
})
// Connecting and Logging In (example with credentials)
telnyxClient.connect(
credentialConfig = CredentialConfig(
sipUser = "your_sip_username",
sipPassword = "your_sip_password",
// ... other config ...
)
)
// Making a call
val outgoingCall = telnyxClient.newInvite(
callerName = "My App",
callerNumber = "+11234567890",
destinationNumber = "+10987654321",
clientState = "some_state"
)
// Observing the specific call's state
outgoingCall.callStateFlow.collect { state ->
if (state is CallState.DONE) {
Log.d("TelnyxClient", "Outgoing call ended. Reason: ${state.reason?.cause}")
}
// Handle other states
}Refer to the SDK's implementation and specific method documentation for detailed usage patterns and configuration options.
使用SharedFlow的推荐方案:
kotlin
// 初始化客户端
val telnyxClient = TelnyxClient(context)
// 使用SharedFlow监听响应(推荐)
lifecycleScope.launch {
telnyxClient.socketResponseFlow.collect { response ->
when (response.status) {
SocketStatus.MESSAGERECEIVED -> {
response.data?.let {
when (it.method) {
SocketMethod.INVITE.methodName -> {
val invite = it.result as InviteResponse
// 处理来电邀请
}
SocketMethod.BYE.methodName -> {
val bye = it.result as com.telnyx.webrtc.sdk.verto.receive.ByeResponse
// 通话被对方结束,可访问bye.cause、bye.sipCode等属性
Log.d("TelnyxClient", "Call ended: ${bye.callId}, Reason: ${bye.cause}")
}
// 处理其他方法如ANSWER、RINGING等
}
}
}
SocketStatus.ERROR -> {
// 处理错误
Log.e("TelnyxClient", "Error: ${response.errorMessage}")
}
// 处理其他状态:ESTABLISHED、LOADING、DISCONNECT
}
}
}使用LiveData的已废弃方案:
kotlin
@Deprecated("Use socketResponseFlow instead. LiveData is deprecated in favor of Kotlin Flows.")
// 监听响应(包括错误和BYE消息)
telnyxClient.socketResponseLiveData.observe(lifecycleOwner, Observer { response ->
when (response.status) {
SocketStatus.MESSAGERECEIVED -> {
response.data?.let {
when (it.method) {
SocketMethod.INVITE.methodName -> {
val invite = it.result as InviteResponse
// 处理来电邀请
}
SocketMethod.BYE.methodName -> {
val bye = it.result as com.telnyx.webrtc.sdk.verto.receive.ByeResponse
// 通话被对方结束,可访问bye.cause、bye.sipCode等属性
Log.d("TelnyxClient", "Call ended: ${bye.callId}, Reason: ${bye.cause}")
}
// 处理其他方法如ANSWER、RINGING等
}
}
}
SocketStatus.ERROR -> {
// 处理错误
Log.e("TelnyxClient", "Error: ${response.errorMessage}")
}
// 处理其他状态:ESTABLISHED、LOADING、DISCONNECT
}
})
// 连接和登录(凭证登录示例)
telnyxClient.connect(
credentialConfig = CredentialConfig(
sipUser = "your_sip_username",
sipPassword = "your_sip_password",
// ... 其他配置 ...
)
)
// 发起通话
val outgoingCall = telnyxClient.newInvite(
callerName = "My App",
callerNumber = "+11234567890",
destinationNumber = "+10987654321",
clientState = "some_state"
)
// 监听特定通话的状态
outgoingCall.callStateFlow.collect { state ->
if (state is CallState.DONE) {
Log.d("TelnyxClient", "Outgoing call ended. Reason: ${state.reason?.cause}")
}
// 处理其他状态
}详细的使用模式和配置选项请参考SDK的实现和具体方法文档。
Telnyx Client
Telnyx客户端
NOTE:
Remember to add and handle INTERNET, RECORD_AUDIO and ACCESS_NETWORK_STATE permissions
<p align="center">
<img align="center" src="https://user-images.githubusercontent.com/9112652/117322479-f4731c00-ae85-11eb-9259-6333fc20b629.png" />
</p>注意:
请记得添加并处理INTERNET、RECORD_AUDIO和ACCESS_NETWORK_STATE权限
<p align="center">
<img align="center" src="https://user-images.githubusercontent.com/9112652/117322479-f4731c00-ae85-11eb-9259-6333fc20b629.png" />
</p>Initialize
初始化
To initialize the TelnyxClient you will have to provide the application context.
kotlin
telnyxClient = TelnyxClient(context)要初始化TelnyxClient,你需要提供应用上下文。
kotlin
telnyxClient = TelnyxClient(context)Connect
连接
Once an instance is created, you can call the one of two available .connect(....) method to connect to the socket.
kotlin
fun connect(
providedServerConfig: TxServerConfiguration = TxServerConfiguration(),
credentialConfig: CredentialConfig,
txPushMetaData: String? = null,
autoLogin: Boolean = true,
)创建实例后,你可以调用两种可用的.connect(....)方法之一来连接到Socket。
kotlin
fun connect(
providedServerConfig: TxServerConfiguration = TxServerConfiguration(),
credentialConfig: CredentialConfig,
txPushMetaData: String? = null,
autoLogin: Boolean = true,
)Listening for events and reacting
监听事件并响应
We need to react for a socket connection state or incoming calls. We do this by getting the Telnyx Socket Response callbacks from our TelnyxClient.
kotlin
val socketResponseFlow: SharedFlow<SocketResponse<ReceivedMessageBody>>我们需要对Socket连接状态或来电做出响应。可以通过TelnyxClient提供的Telnyx Socket Response回调来实现。
kotlin
val socketResponseFlow: SharedFlow<SocketResponse<ReceivedMessageBody>>Call
Call
Telnyx Call
Telnyx Call
Class that represents a Call and handles all call related actions, including answering and ending a call.
代表一个通话的类,处理所有与通话相关的操作,包括接听和结束通话。
Creating a call invitation
创建通话邀请
In order to make a call invitation, you need to provide your callerName, callerNumber, the destinationNumber (or SIP credential), and your clientState (any String value).
kotlin
telnyxClient.call.newInvite(callerName, callerNumber, destinationNumber, clientState)要发起通话邀请,你需要提供callerName、callerNumber、destinationNumber(或SIP凭证)以及clientState(任意字符串值)。
kotlin
telnyxClient.call.newInvite(callerName, callerNumber, destinationNumber, clientState)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 as LiveData:
kotlin
fun getSocketResponse(): LiveData<SocketResponse<ReceivedMessageBody>>? =
telnyxClient.getSocketResponse()要能够接听通话,我们首先需要监听邀请。可以通过获取Telnyx Socket Response的LiveData实现:
kotlin
fun getSocketResponse(): LiveData<SocketResponse<ReceivedMessageBody>>? =
telnyxClient.getSocketResponse()Handling Multiple Calls
处理多路通话
The Telnyx WebRTC SDK allows for multiple calls to be handled at once. You can use the callId to differentiate the calls..
Telnyx WebRTC SDK支持同时处理多路通话。你可以使用callId来区分不同的通话。
Key Properties
关键属性
- : A unique identifier for the call.
callId: UUID - : The session ID associated with the Telnyx connection.
sessionId: String - : A Kotlin Flow that emits updates to the call's current state. This is the primary way to observe real-time changes to the call. States include:
callStateFlow: StateFlow<CallState>- : The call has been locally initiated but not yet sent.
CallState.NEW - : The call is in the process of connecting.
CallState.CONNECTING - : The call invitation has been sent, and the remote party is being alerted.
CallState.RINGING - : The call is established and active.
CallState.ACTIVE - : The call is on hold.
CallState.HELD - : The call has ended. The optional
CallState.DONE(reason: CallTerminationReason?)parameter provides details about why the call terminated (e.g., normal hangup, call rejected, busy, SIP error).reasoncontainsCallTerminationReason,cause,causeCode, andsipCode.sipReason - : An error occurred related to this call.
CallState.ERROR - : The call was dropped, typically due to network issues. The
CallState.DROPPED(reason: CallNetworkChangeReason)(reasonorCallNetworkChangeReason.NETWORK_LOST) provides context.CallNetworkChangeReason.NETWORK_SWITCH - : The SDK is attempting to reconnect the call after a network disruption. The
CallState.RECONNECTING(reason: CallNetworkChangeReason)provides context.reason
- : A callback for real-time call quality metrics.
onCallQualityChange: ((CallQualityMetrics) -> Unit)? - : Reference to the Android
audioManager: AudioManagerfor controlling audio settings.AudioManager - : Represents the underlying WebRTC peer connection.
peerConnection: Peer?
- :通话的唯一标识符。
callId: UUID - :与Telnyx连接关联的会话ID。
sessionId: String - :Kotlin Flow,发送通话当前状态的更新。这是观察通话实时变化的主要方式。状态包括:
callStateFlow: StateFlow<CallState>- :通话已在本地发起但尚未发送。
CallState.NEW - :通话正在连接中。
CallState.CONNECTING - :通话邀请已发送,正在提醒对方。
CallState.RINGING - :通话已建立且处于活跃状态。
CallState.ACTIVE - :通话已被保持。
CallState.HELD - :通话已结束。可选的
CallState.DONE(reason: CallTerminationReason?)参数提供了通话终止的详细原因(例如正常挂断、通话被拒、忙线、SIP错误)。reason包含CallTerminationReason、cause、causeCode和sipCode。sipReason - :该通话发生了错误。
CallState.ERROR - :通话已掉线,通常是由于网络问题。
CallState.DROPPED(reason: CallNetworkChangeReason)(reason或CallNetworkChangeReason.NETWORK_LOST)提供了上下文信息。CallNetworkChangeReason.NETWORK_SWITCH - :SDK正在尝试在网络中断后重新连接通话。
CallState.RECONNECTING(reason: CallNetworkChangeReason)提供了上下文信息。reason
- :实时通话质量指标的回调。
onCallQualityChange: ((CallQualityMetrics) -> Unit)? - :Android
audioManager: AudioManager的引用,用于控制音频设置。AudioManager - :代表底层WebRTC对等连接。
peerConnection: Peer?
Key Methods
关键方法
- : (Typically initiated via
newInvite(...)) Initiates a new outgoing call.TelnyxClient - : (Typically initiated via
acceptCall(...)) Accepts an incoming call.TelnyxClient - : Terminates the call. This is usually called on the
endCall(callId: UUID)which then manages the specificTelnyxClientobject.Call - : Toggles the microphone mute state.
onMuteUnmutePressed() - : Toggles the loudspeaker state.
onLoudSpeakerPressed() - : Toggles the hold state for the call.
onHoldUnholdPressed(callId: UUID) - : Sends DTMF tones.
dtmf(callId: UUID, tone: String)
- :(通常通过
newInvite(...)发起)发起新的外呼通话。TelnyxClient - :(通常通过
acceptCall(...)发起)接听来电。TelnyxClient - :终止通话。通常在
endCall(callId: UUID)上调用,由它管理对应的TelnyxClient对象。Call - :切换麦克风静音状态。
onMuteUnmutePressed() - :切换扬声器状态。
onLoudSpeakerPressed() - :切换通话的保持状态。
onHoldUnholdPressed(callId: UUID) - :发送DTMF音。
dtmf(callId: UUID, tone: String)
Observing Call State
监听通话状态
Applications should observe the to react to changes in the call's status and update the UI accordingly. For example, displaying call duration when , showing a "reconnecting" indicator when , or presenting termination reasons when .
callStateFlowACTIVERECONNECTINGDONEkotlin
// Example: Observing call state in a ViewModel or Composable
viewModelScope.launch {
myCall.callStateFlow.collect { state ->
when (state) {
is CallState.ACTIVE -> {
// Update UI to show active call controls
}
is CallState.DONE -> {
// Call has ended, update UI
// Access state.reason for termination details
val reasonDetails = state.reason?.let {
"Cause: ${it.cause}, SIP Code: ${it.sipCode}"
} ?: "No specific reason provided."
Log.d("Call Ended", "Reason: $reasonDetails")
}
is CallState.DROPPED -> {
// Call dropped, possibly show a message with state.reason.description
Log.d("Call Dropped", "Reason: ${state.callNetworkChangeReason.description}")
}
is CallState.RECONNECTING -> {
// Call is reconnecting, update UI
Log.d("Call Reconnecting", "Reason: ${state.callNetworkChangeReason.description}")
}
// Handle other states like NEW, CONNECTING, RINGING, HELD, ERROR
else -> { /* ... */ }
}
}
}For more details on specific parameters and advanced usage, refer to the SDK's source code and the main documentation.
TelnyxClient应用应该监听以响应通话状态的变化,并相应地更新UI。例如,当状态为时显示通话时长,当状态为时显示“正在重连”指示器,或当状态为时展示终止原因。
callStateFlowACTIVERECONNECTINGDONEkotlin
// 示例:在ViewModel或Composable中监听通话状态
viewModelScope.launch {
myCall.callStateFlow.collect { state ->
when (state) {
is CallState.ACTIVE -> {
// 更新UI以展示活跃通话控件
}
is CallState.DONE -> {
// 通话已结束,更新UI
// 访问state.reason获取终止详情
val reasonDetails = state.reason?.let {
"Cause: ${it.cause}, SIP Code: ${it.sipCode}"
} ?: "未提供具体原因。"
Log.d("Call Ended", "Reason: $reasonDetails")
}
is CallState.DROPPED -> {
// 通话已掉线,可展示包含state.reason.description的提示
Log.d("Call Dropped", "Reason: ${state.callNetworkChangeReason.description}")
}
is CallState.RECONNECTING -> {
// 通话正在重连,更新UI
Log.d("Call Reconnecting", "Reason: ${state.callNetworkChangeReason.description}")
}
// 处理其他状态如NEW、CONNECTING、RINGING、HELD、ERROR
else -> { /* ... */ }
}
}
}特定参数的更多详情和高级用法请参考SDK源代码和主文档。
TelnyxClientReceivedMessageBody
ReceivedMessageBody
ReceivedMessageBody
ReceivedMessageBody
A data class the represents the structure of every message received via the socket connection
kotlin
data class ReceivedMessageBody(val method: String, val result: ReceivedResult?)Where the params are:
- method the Telnyx Message Method - ie. INVITE, BYE, MODIFY, etc. @see [SocketMethod]
- result the content of the actual message in the structure provided via
ReceivedResult
一个数据类,代表通过Socket连接收到的每条消息的结构
kotlin
data class ReceivedMessageBody(val method: String, val result: ReceivedResult?)参数说明:
- method Telnyx消息方法 —— 例如INVITE、BYE、MODIFY等。@see [SocketMethod]
- result 实际消息的内容,结构由定义
ReceivedResult
SocketMethod
SocketMethod
Enum class to detail the Method property of the response from the Telnyx WEBRTC client with the given [methodName]
枚举类,详细说明Telnyx WEBRTC客户端响应的Method属性和对应的[methodName]
Structure
结构
kotlin
data class ReceivedMessageBody(
val method: String, // The Telnyx Message Method (e.g., "telnyx_rtc.invite", "telnyx_rtc.bye")
val result: ReceivedResult? // The content of the actual message
)-
: This field indicates the type of message received. It corresponds to one of the
method: Stringenums (e.g.,SocketMethod,SocketMethod.INVITE,SocketMethod.ANSWER). Your application will typically use this field in aSocketMethod.BYEstatement to determine how to process thewhen.result -
: This field holds the actual payload of the message.
result: ReceivedResult?is a sealed class, and the concrete type ofReceivedResultwill depend on theresult. For example:method- If is
method,SocketMethod.LOGIN.methodNamewill be aresult.LoginResponse - If is
method,SocketMethod.INVITE.methodNamewill be anresult.InviteResponse - If is
method,SocketMethod.ANSWER.methodNamewill be anresult.AnswerResponse - If is
method,SocketMethod.BYE.methodNamewill be aresult. Importantly, thiscom.telnyx.webrtc.sdk.verto.receive.ByeResponsenow includes detailed termination information such asByeResponse,cause,causeCode, andsipCode, in addition to thesipReason.callId - Other subtypes include
ReceivedResult,RingingResponse, andMediaResponse.DisablePushResponse
- If
kotlin
data class ReceivedMessageBody(
val method: String, // Telnyx消息方法(例如"telnyx_rtc.invite"、"telnyx_rtc.bye")
val result: ReceivedResult? // 实际消息的内容
)-
:该字段表示收到的消息类型。对应
method: String枚举中的一个值(例如SocketMethod、SocketMethod.INVITE、SocketMethod.ANSWER)。你的应用通常会在SocketMethod.BYE语句中使用该字段来决定如何处理when。result -
:该字段保存消息的实际负载。
result: ReceivedResult?是一个密封类,ReceivedResult的具体类型取决于result。例如:method- 如果是
method,SocketMethod.LOGIN.methodName将是result类型。LoginResponse - 如果是
method,SocketMethod.INVITE.methodName将是result类型。InviteResponse - 如果是
method,SocketMethod.ANSWER.methodName将是result类型。AnswerResponse - 如果是
method,SocketMethod.BYE.methodName将是result类型。重要的是,这个com.telnyx.webrtc.sdk.verto.receive.ByeResponse现在包含了详细的终止信息,除了ByeResponse之外,还有callId、cause、causeCode和sipCode。sipReason - 其他子类型包括
ReceivedResult、RingingResponse和MediaResponse。DisablePushResponse
- 如果
Usage
用法
When you observe , you receive a . If the status is , the field of will contain the .
TelnyxClient.socketResponseLiveDataSocketResponse<ReceivedMessageBody>SocketStatus.MESSAGERECEIVEDdataSocketResponseReceivedMessageBodykotlin
telnyxClient.socketResponseLiveData.observe(this, Observer { response ->
if (response.status == SocketStatus.MESSAGERECEIVED) {
response.data?.let { receivedMessageBody ->
Log.d("SDK_APP", "Method: ${receivedMessageBody.method}")
when (receivedMessageBody.method) {
SocketMethod.LOGIN.methodName -> {
val loginResponse = receivedMessageBody.result as? LoginResponse
// Process login response
}
SocketMethod.INVITE.methodName -> {
val inviteResponse = receivedMessageBody.result as? InviteResponse
// Process incoming call invitation
}
SocketMethod.BYE.methodName -> {
val byeResponse = receivedMessageBody.result as? com.telnyx.webrtc.sdk.verto.receive.ByeResponse
byeResponse?.let {
// Process call termination, access it.cause, it.sipCode, etc.
Log.i("SDK_APP", "Call ${it.callId} ended. Reason: ${it.cause}, SIP Code: ${it.sipCode}")
}
}
// Handle other methods...
}
}
}
})By checking the and casting the to its expected type, your application can effectively handle the diverse messages sent by the Telnyx platform.
<!-- END AUTO-GENERATED API REFERENCE -->methodresult当你监听时,你会收到。如果状态为,的字段将包含。
TelnyxClient.socketResponseLiveDataSocketResponse<ReceivedMessageBody>SocketStatus.MESSAGERECEIVEDSocketResponsedataReceivedMessageBodykotlin
telnyxClient.socketResponseLiveData.observe(this, Observer { response ->
if (response.status == SocketStatus.MESSAGERECEIVED) {
response.data?.let { receivedMessageBody ->
Log.d("SDK_APP", "Method: ${receivedMessageBody.method}")
when (receivedMessageBody.method) {
SocketMethod.LOGIN.methodName -> {
val loginResponse = receivedMessageBody.result as? LoginResponse
// 处理登录响应
}
SocketMethod.INVITE.methodName -> {
val inviteResponse = receivedMessageBody.result as? InviteResponse
// 处理来电邀请
}
SocketMethod.BYE.methodName -> {
val byeResponse = receivedMessageBody.result as? com.telnyx.webrtc.sdk.verto.receive.ByeResponse
byeResponse?.let {
// 处理通话终止,访问it.cause、it.sipCode等属性
Log.i("SDK_APP", "Call ${it.callId} ended. Reason: ${it.cause}, SIP Code: ${it.sipCode}")
}
}
// 处理其他方法...
}
}
}
})通过检查并将转换为预期类型,你的应用可以有效处理Telnyx平台发送的各种消息。
<!-- END AUTO-GENERATED API REFERENCE -->methodresult