telnyx-webrtc-client-android

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Telnyx 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 the
telnyx-webrtc-*
skill in your server language plugin (e.g.,
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.gradle
:
gradle
allprojects {
    repositories {
        maven { url 'https://jitpack.io' }
    }
}
Add the dependency:
gradle
dependencies {
    implementation 'com.github.team-telnyx:telnyx-webrtc-android:latest-version'
}
将JitPack仓库添加到项目的
build.gradle
文件中:
gradle
allprojects {
    repositories {
        maven { url 'https://jitpack.io' }
    }
}
添加依赖:
gradle
dependencies {
    implementation 'com.github.team-telnyx:telnyx-webrtc-android:latest-version'
}

Required Permissions

所需权限

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.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.xml
文件中:
xml
<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

配置选项

ParameterTypeDescription
sipUser
/
sipToken
StringCredentials from Telnyx Portal
sipCallerIDName
String?Caller ID name displayed to recipients
sipCallerIDNumber
String?Caller ID number
fcmToken
String?Firebase Cloud Messaging token for push
ringtone
Any?Raw resource ID or URI for ringtone
ringBackTone
Int?Raw resource ID for ringback tone
logLevel
LogLevelNONE, ERROR, WARNING, DEBUG, INFO, ALL
autoReconnect
BooleanAuto-retry login on failure (3 attempts)
region
RegionAUTO, US_EAST, US_WEST, EU_WEST

参数类型描述
sipUser
/
sipToken
String来自Telnyx门户的凭证
sipCallerIDName
String?向接收方展示的来电显示名称
sipCallerIDNumber
String?来电显示号码
fcmToken
String?用于推送的Firebase Cloud Messaging令牌
ringtone
Any?铃声的原生资源ID或URI
ringBackTone
Int?回铃音的原生资源ID
logLevel
LogLevelNONE, ERROR, WARNING, DEBUG, INFO, ALL
autoReconnect
Boolean登录失败时自动重试(最多3次)
region
RegionAUTO, 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
FirebaseMessagingService
:
kotlin
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)
    }
}
在你的
FirebaseMessagingService
中:
kotlin
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 automatically
kotlin
// 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 LevelMOS Range
EXCELLENT> 4.2
GOOD4.1 - 4.2
FAIR3.7 - 4.0
POOR3.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
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 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.pro
:
proguard
-keep class com.telnyx.webrtc.** { *; }
-dontwarn kotlin.Experimental$Level
-dontwarn kotlin.Experimental
-dontwarn kotlinx.coroutines.scheduling.ExperimentalCoroutineDispatcher

如果使用代码混淆,请将以下规则添加到
proguard-rules.pro
中:
proguard
-keep class com.telnyx.webrtc.** { *; }
-dontwarn kotlin.Experimental$Level
-dontwarn kotlin.Experimental
-dontwarn kotlinx.coroutines.scheduling.ExperimentalCoroutineDispatcher

Troubleshooting

问题排查

IssueSolution
No audioCheck RECORD_AUDIO permission is granted
Push not receivedVerify FCM token is passed in config
Login failsVerify SIP credentials in Telnyx Portal
Call dropsCheck network stability, enable
autoReconnect
sender_id_mismatch (push)FCM project mismatch - ensure app's
google-services.json
matches server credentials
<!-- 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.
问题解决方案
没有声音检查RECORD_AUDIO权限已被授予
收不到推送验证配置中传入了正确的FCM令牌
登录失败验证Telnyx门户中的SIP凭证是否正确
通话掉线检查网络稳定性,开启
autoReconnect
配置
sender_id_mismatch(推送相关)FCM项目不匹配 —— 确保应用的
google-services.json
与服务端凭证一致
<!-- BEGIN AUTO-GENERATED API REFERENCE -- do not edit below this line -->
references/webrtc-server-api.md包含服务端WebRTC API相关内容 —— 凭证创建、令牌生成和推送通知配置。在设置身份验证或推送通知时你必须阅读该文档。

API Reference

API参考

TelnyxClient

TelnyxClient

TelnyxClient
is the main entry point for interacting with the Telnyx WebRTC SDK. It handles connection management, call creation, and responses from the Telnyx platform.
TelnyxClient
是与Telnyx WebRTC SDK交互的主要入口。它负责处理连接管理、通话创建以及Telnyx平台的响应。

Core 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 (
    newInvite
    ), accept (
    acceptCall
    ), and end (
    endCall
    ) calls.
  • Event Handling: Uses
    TxSocketListener
    to process events from the socket, such as incoming calls (
    onOfferReceived
    ), call answers (
    onAnswerReceived
    ), call termination (
    onByeReceived
    ), and errors (
    onErrorReceived
    ).
  • State Exposure: Exposes connection status, session information, and call events via
    SharedFlow
    (recommended:
    socketResponseFlow
    ) and deprecated
    LiveData
    (e.g.,
    socketResponseLiveData
    ) for UI consumption.
  • 连接管理:建立并维护与Telnyx RTC平台的WebSocket连接。
  • 身份验证:支持通过SIP凭证或令牌进行身份验证。
  • 通话控制:提供发起(
    newInvite
    )、接听(
    acceptCall
    )和结束(
    endCall
    )通话的方法。
  • 事件处理:使用
    TxSocketListener
    处理来自Socket的事件,例如来电(
    onOfferReceived
    )、通话被接听(
    onAnswerReceived
    )、通话结束(
    onByeReceived
    )和错误(
    onErrorReceived
    )。
  • 状态暴露:通过
    SharedFlow
    (推荐使用
    socketResponseFlow
    )和已废弃的
    LiveData
    (例如
    socketResponseLiveData
    )暴露连接状态、会话信息和通话事件,供UI层消费。

Key Components and Interactions

关键组件与交互逻辑

  • TxSocket
    : Manages the underlying WebSocket communication.
  • TxSocketListener
    : An interface implemented by
    TelnyxClient
    to receive and process socket events. Notably:
    • onOfferReceived(jsonObject: JsonObject)
      : Handles incoming call invitations.
    • onAnswerReceived(jsonObject: JsonObject)
      : Processes answers to outgoing calls.
    • onByeReceived(jsonObject: JsonObject)
      : Handles call termination notifications. The
      jsonObject
      now contains richer details including
      cause
      ,
      causeCode
      ,
      sipCode
      , and
      sipReason
      , allowing the client to populate
      CallState.DONE
      with a detailed
      CallTerminationReason
      .
    • onErrorReceived(jsonObject: JsonObject)
      : Manages errors reported by the socket or platform.
    • onClientReady(jsonObject: JsonObject)
      : Indicates the client is ready for operations after connection and initial setup.
    • onGatewayStateReceived(gatewayState: String, receivedSessionId: String?)
      : Provides updates on the registration status with the Telnyx gateway.
  • Call
    Class
    : Represents individual call sessions.
    TelnyxClient
    creates and manages instances of
    Call
    .
  • CallState
    : The client updates the
    CallState
    of individual
    Call
    objects based on socket events and network conditions. This includes states like
    DROPPED(reason: CallNetworkChangeReason)
    ,
    RECONNECTING(reason: CallNetworkChangeReason)
    , and
    DONE(reason: CallTerminationReason?)
    which now provide more context.
  • socketResponseFlow: SharedFlow<SocketResponse<ReceivedMessageBody>>
    : This SharedFlow stream is the recommended approach for applications. It emits
    SocketResponse
    objects that wrap messages received from the Telnyx platform. For
    BYE
    messages, the
    ReceivedMessageBody
    will contain a
    com.telnyx.webrtc.sdk.verto.receive.ByeResponse
    which is now enriched with termination cause details.
  • socketResponseLiveData: LiveData<SocketResponse<ReceivedMessageBody>>
    : [DEPRECATED] This LiveData stream is deprecated in favor of
    socketResponseFlow
    . It's maintained for backward compatibility but new implementations should use SharedFlow.
  • TxSocket
    :管理底层WebSocket通信。
  • TxSocketListener
    :由
    TelnyxClient
    实现的接口,用于接收和处理Socket事件。主要包括:
    • onOfferReceived(jsonObject: JsonObject)
      :处理来电邀请。
    • onAnswerReceived(jsonObject: JsonObject)
      :处理外呼的接听响应。
    • onByeReceived(jsonObject: JsonObject)
      :处理通话结束通知。现在
      jsonObject
      包含更丰富的详情,包括
      cause
      causeCode
      sipCode
      sipReason
      ,允许客户端为
      CallState.DONE
      填充详细的
      CallTerminationReason
    • onErrorReceived(jsonObject: JsonObject)
      :处理Socket或平台上报的错误。
    • onClientReady(jsonObject: JsonObject)
      :表示客户端在连接和初始设置完成后已准备好处理操作。
    • onGatewayStateReceived(gatewayState: String, receivedSessionId: String?)
      :提供与Telnyx网关的注册状态更新。
  • Call
    :代表单个通话会话。
    TelnyxClient
    负责创建和管理
    Call
    实例。
  • CallState
    :客户端根据Socket事件和网络条件更新单个
    Call
    对象的
    CallState
    。包含的状态有
    DROPPED(reason: CallNetworkChangeReason)
    RECONNECTING(reason: CallNetworkChangeReason)
    DONE(reason: CallTerminationReason?)
    ,现在这些状态都提供了更多上下文信息。
  • socketResponseFlow: SharedFlow<SocketResponse<ReceivedMessageBody>>
    :推荐应用使用的SharedFlow流。它会发送封装了从Telnyx平台收到的消息的
    SocketResponse
    对象。对于
    BYE
    消息,
    ReceivedMessageBody
    会包含
    com.telnyx.webrtc.sdk.verto.receive.ByeResponse
    ,现在该对象已补充了通话结束原因的详细信息。
  • socketResponseLiveData: LiveData<SocketResponse<ReceivedMessageBody>>
    [已废弃] 该LiveData流已被弃用,推荐使用
    socketResponseFlow
    。它会被保留以保证向后兼容,但新的实现应该使用SharedFlow。

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

关键属性

  • callId: UUID
    : A unique identifier for the call.
  • sessionId: String
    : The session ID associated with the Telnyx connection.
  • callStateFlow: StateFlow<CallState>
    : 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:
    • CallState.NEW
      : The call has been locally initiated but not yet sent.
    • CallState.CONNECTING
      : The call is in the process of connecting.
    • CallState.RINGING
      : The call invitation has been sent, and the remote party is being alerted.
    • CallState.ACTIVE
      : The call is established and active.
    • CallState.HELD
      : The call is on hold.
    • CallState.DONE(reason: CallTerminationReason?)
      : The call has ended. The optional
      reason
      parameter provides details about why the call terminated (e.g., normal hangup, call rejected, busy, SIP error).
      CallTerminationReason
      contains
      cause
      ,
      causeCode
      ,
      sipCode
      , and
      sipReason
      .
    • CallState.ERROR
      : An error occurred related to this call.
    • CallState.DROPPED(reason: CallNetworkChangeReason)
      : The call was dropped, typically due to network issues. The
      reason
      (
      CallNetworkChangeReason.NETWORK_LOST
      or
      CallNetworkChangeReason.NETWORK_SWITCH
      ) provides context.
    • CallState.RECONNECTING(reason: CallNetworkChangeReason)
      : The SDK is attempting to reconnect the call after a network disruption. The
      reason
      provides context.
  • onCallQualityChange: ((CallQualityMetrics) -> Unit)?
    : A callback for real-time call quality metrics.
  • audioManager: AudioManager
    : Reference to the Android
    AudioManager
    for controlling audio settings.
  • peerConnection: Peer?
    : Represents the underlying WebRTC peer connection.
  • callId: UUID
    :通话的唯一标识符。
  • sessionId: String
    :与Telnyx连接关联的会话ID。
  • callStateFlow: StateFlow<CallState>
    :Kotlin Flow,发送通话当前状态的更新。这是观察通话实时变化的主要方式。状态包括:
    • CallState.NEW
      :通话已在本地发起但尚未发送。
    • CallState.CONNECTING
      :通话正在连接中。
    • CallState.RINGING
      :通话邀请已发送,正在提醒对方。
    • CallState.ACTIVE
      :通话已建立且处于活跃状态。
    • CallState.HELD
      :通话已被保持。
    • CallState.DONE(reason: CallTerminationReason?)
      :通话已结束。可选的
      reason
      参数提供了通话终止的详细原因(例如正常挂断、通话被拒、忙线、SIP错误)。
      CallTerminationReason
      包含
      cause
      causeCode
      sipCode
      sipReason
    • CallState.ERROR
      :该通话发生了错误。
    • CallState.DROPPED(reason: CallNetworkChangeReason)
      :通话已掉线,通常是由于网络问题。
      reason
      CallNetworkChangeReason.NETWORK_LOST
      CallNetworkChangeReason.NETWORK_SWITCH
      )提供了上下文信息。
    • CallState.RECONNECTING(reason: CallNetworkChangeReason)
      :SDK正在尝试在网络中断后重新连接通话。
      reason
      提供了上下文信息。
  • onCallQualityChange: ((CallQualityMetrics) -> Unit)?
    :实时通话质量指标的回调。
  • audioManager: AudioManager
    :Android
    AudioManager
    的引用,用于控制音频设置。
  • peerConnection: Peer?
    :代表底层WebRTC对等连接。

Key Methods

关键方法

  • newInvite(...)
    : (Typically initiated via
    TelnyxClient
    ) Initiates a new outgoing call.
  • acceptCall(...)
    : (Typically initiated via
    TelnyxClient
    ) Accepts an incoming call.
  • endCall(callId: UUID)
    : Terminates the call. This is usually called on the
    TelnyxClient
    which then manages the specific
    Call
    object.
  • onMuteUnmutePressed()
    : Toggles the microphone mute state.
  • onLoudSpeakerPressed()
    : Toggles the loudspeaker state.
  • onHoldUnholdPressed(callId: UUID)
    : Toggles the hold state for the call.
  • dtmf(callId: UUID, tone: String)
    : Sends DTMF tones.
  • newInvite(...)
    :(通常通过
    TelnyxClient
    发起)发起新的外呼通话。
  • acceptCall(...)
    :(通常通过
    TelnyxClient
    发起)接听来电。
  • endCall(callId: UUID)
    :终止通话。通常在
    TelnyxClient
    上调用,由它管理对应的
    Call
    对象。
  • onMuteUnmutePressed()
    :切换麦克风静音状态。
  • onLoudSpeakerPressed()
    :切换扬声器状态。
  • onHoldUnholdPressed(callId: UUID)
    :切换通话的保持状态。
  • dtmf(callId: UUID, tone: String)
    :发送DTMF音。

Observing Call State

监听通话状态

Applications should observe the
callStateFlow
to react to changes in the call's status and update the UI accordingly. For example, displaying call duration when
ACTIVE
, showing a "reconnecting" indicator when
RECONNECTING
, or presenting termination reasons when
DONE
.
kotlin
// 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
TelnyxClient
documentation.
应用应该监听
callStateFlow
以响应通话状态的变化,并相应地更新UI。例如,当状态为
ACTIVE
时显示通话时长,当状态为
RECONNECTING
时显示“正在重连”指示器,或当状态为
DONE
时展示终止原因。
kotlin
// 示例:在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源代码和
TelnyxClient
主文档。

ReceivedMessageBody

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
)
  • method: String
    : This field indicates the type of message received. It corresponds to one of the
    SocketMethod
    enums (e.g.,
    SocketMethod.INVITE
    ,
    SocketMethod.ANSWER
    ,
    SocketMethod.BYE
    ). Your application will typically use this field in a
    when
    statement to determine how to process the
    result
    .
  • result: ReceivedResult?
    : This field holds the actual payload of the message.
    ReceivedResult
    is a sealed class, and the concrete type of
    result
    will depend on the
    method
    . For example:
    • If
      method
      is
      SocketMethod.LOGIN.methodName
      ,
      result
      will be a
      LoginResponse
      .
    • If
      method
      is
      SocketMethod.INVITE.methodName
      ,
      result
      will be an
      InviteResponse
      .
    • If
      method
      is
      SocketMethod.ANSWER.methodName
      ,
      result
      will be an
      AnswerResponse
      .
    • If
      method
      is
      SocketMethod.BYE.methodName
      ,
      result
      will be a
      com.telnyx.webrtc.sdk.verto.receive.ByeResponse
      . Importantly, this
      ByeResponse
      now includes detailed termination information such as
      cause
      ,
      causeCode
      ,
      sipCode
      , and
      sipReason
      , in addition to the
      callId
      .
    • Other
      ReceivedResult
      subtypes include
      RingingResponse
      ,
      MediaResponse
      , and
      DisablePushResponse
      .
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
TelnyxClient.socketResponseLiveData
, you receive a
SocketResponse<ReceivedMessageBody>
. If the status is
SocketStatus.MESSAGERECEIVED
, the
data
field of
SocketResponse
will contain the
ReceivedMessageBody
.
kotlin
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
method
and casting the
result
to its expected type, your application can effectively handle the diverse messages sent by the Telnyx platform.
<!-- END AUTO-GENERATED API REFERENCE -->
当你监听
TelnyxClient.socketResponseLiveData
时,你会收到
SocketResponse<ReceivedMessageBody>
。如果状态为
SocketStatus.MESSAGERECEIVED
SocketResponse
data
字段将包含
ReceivedMessageBody
kotlin
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}")
                    }
                }
                // 处理其他方法...
            }
        }
    }
})
通过检查
method
并将
result
转换为预期类型,你的应用可以有效处理Telnyx平台发送的各种消息。
<!-- END AUTO-GENERATED API REFERENCE -->