音視訊通話
本頁講 Android 上的一對一和群組音視訊通話:發起、來電、接聽、結束通話,以及影片畫面和音訊裝置。呼叫和接聽由 im.calls 處理;音影片媒體、音訊裝置和系統來電介面由 im-call 模組提供,媒體經過平臺部署的 LiveKit 服務。
使用前:平臺要先配置好媒體服務,併為應用開啟音影片。媒體服務的金鑰只在服務端,App 不需要、也不能填寫。
| 要做什麼 | 看哪裡 |
|---|---|
| 引入模組、宣告來電頁、申請許可權 | 安裝和許可權 |
| 發起、接聽、結束通話 | 發起、接聽與結束 |
| 顯示通話狀態、查通話記錄 | 狀態與歷史 |
| 顯示影片、切換攝像頭和揚聲器 | 影片和音訊裝置 |
| 鎖屏來電、系統通話介面 | 系統來電和後臺 |
| 餘額不足時的處理 | 應用餘額與服務准入 |
安裝和許可權
引入 im-call,配置概述中的 JitPack 倉庫。初始化時提供 DRCallOptions:
import com.deeprespond.im.*
import com.deeprespond.im.call.*
val options = DRClientOptions(
appKey = "org#app",
apiUrl = "https://api.example.com",
call = DRCallOptions(incomingCallActivity = IncomingCallActivity::class.java),
)IncomingCallActivity 是你 App 自己的來電頁(全屏來電和點“接聽”時開啟),必須在清單中宣告(見下);不傳 incomingCallActivity 時開啟 App 的啟動 Activity。SDK 的清單已經宣告瞭通話服務、通知、音訊、攝像頭等許可權,但執行時的授權要由 App 自己申請:
- 語音通話需要
RECORD_AUDIO,視訊通話另需CAMERA; - 通知和藍芽許可權按系統版本申請;
- Android 14 起,全屏通知能否使用、Google Play 上的許可權宣告,都由 App 負責。
<activity
android:name=".IncomingCallActivity"
android:exported="false"
android:showWhenLocked="true"
android:turnScreenOn="true" />DRCallOptions 還有:
| 選項 | 預設值 | 說明 |
|---|---|---|
useTelecom | true | 接入系統的通話框架(Jetpack Core-Telecom,Android 8 起) |
autoBusy | true | 使用者正在打電話或在其他 App 中通話時,來電自動以忙線拒絕 |
ringtone | 系統的來電鈴聲 | 來電鈴聲,只在第一次建立來電通知渠道時生效 |
需要在 App 沒有執行時也收到來電,還要配置推送。calls.supported 為 true 才說明媒體能力已經接入;能呼叫 im.calls 不代表媒體已經配好。
發起、接聽與結束
import com.deeprespond.im.*
val call = im.calls.start(CallMedia.AUDIO, CallTarget.User("bob"))
// 拿到句柄后,按业务界面管理当前通话。
println(call.callId)- 群通話用
CallTarget.Group(groupId, usernames?);視訊通話把CallMedia.AUDIO換成VIDEO。 incoming是還沒處理的來電(StateFlow),current是當前的通話。- 收到
CallIncoming事件或incoming變化時顯示來電頁,拿到這通電話的CallHandle:
call.join() // 用户接听。
call.setMicrophoneEnabled(false)
call.setCameraEnabled(false)
call.hangup() // 本设备退出通话。| 方法 | 作用 |
|---|---|
join() | 接聽來電,或加入進行中的群通話 |
reject(reason) | 拒接,reason 為 DECLINED(拒絕)或 BUSY(忙線) |
hangup() | 本人離開通話,其他人可以繼續 |
end() | 結束整個通話,所有人都會結束通話(需要許可權) |
invite(usernames) | 邀請更多人,返回每個人的結果 |
resume() | 恢復中斷的媒體連線 |
注意 hangup 和 end 的區別:普通的“結束通話”按鈕用 hangup。
狀態與歷史
call.snapshot是通話的狀態,包括服務端的通話資訊和本地的媒體狀態;call.tracks是音影片軌道。call.data接收通話中的資料訊息,sendData(ByteArray)傳送。它們只在通話期間有效,不能代替可靠的聊天訊息。get(callId)取得一通電話的控制代碼,history(cursor?, limit?)分頁查詢通話記錄。groupCall(groupId)取得群裡正在進行的通話,groupCallBanner返回“群通話進行中”橫幅需要的資訊。- 通話變化時發出
CallChanged、GroupCallChanged,據此更新介面。
影片和音訊裝置
import com.deeprespond.im.call.*
val view = DRCallVideoView(context)
view.scaleType = DRCallVideoView.ScaleType.FIT
view.mirror = false
val track = call.tracks.value.local
view.bind(call, track)
// 轨道变化时重新 bind;页面不显示时 unbind。
view.unbind()DRCallVideoView 要真正加入檢視樹才會顯示;bind 的軌道可以為 null(不顯示畫面)。本地或遠端的軌道變化時重新繫結,不要快取舊的軌道。
import com.deeprespond.im.call.*
call.switchCamera()
call.setSpeakerphoneOn(true)
val devices = call.audioEndpoints.value
val selected = devices.available.firstOrNull()
if (selected != null) call.setAudioEndpoint(selected)audioEndpoints 是 StateFlow,包含可用的裝置 available 和當前的裝置 current,型別有耳機、聽筒、揚聲器、藍芽和流媒體裝置。缺少許可權或裝置狀態不對時,切換可能失敗。
系統來電和後臺
DRCallUI.of(im) 返回系統來電介面的控制器,沒有配置 call 選項時為 null:
| 方法 | 作用 |
|---|---|
canUseFullScreenIntent / openFullScreenIntentSettings | 檢查能否使用全屏來電通知,開啟對應的系統設定 |
callChannelEnabled | 檢查來電的通知渠道有沒有被關閉 |
intentCall(intent) | 從啟動來電頁的 Intent 中取出對應的通話 |
actions | 收集使用者在通知或系統通話介面上的操作(接聽、拒接等) |
SDK 用 Core-Telecom 接入系統通話,用前臺服務在後臺保持通話。App 要負責申請許可權、實現鎖屏來電頁、處理頁面生命週期。後臺通話、程序被殺後被來電喚醒,以及各手機品牌的省電策略,請在真機上逐一驗證。完整的介面見 CallHandle。
獨立頻道
本頁的呼叫、振鈴、接聽都屬於通話。不需要 IM 群的會議、語音房請用獨立 RTC 頻道:頻道沒有振鈴,不使用來電介面和來電通知。兩者共用同一套媒體服務,但分開計費。
應用餘額與服務准入
使用新計費的應用,通話和獨立頻道共用本應用的音影片標準時長餘額。能否發起通話由服務端檢查:
- 餘額要大於 0;
- 應用策略允許,同時進行的通話和頻道數沒有超出上限;
- 平臺已配置能計量用量的媒體服務。
calls.supported 只說明這臺裝置有媒體能力,不代表餘額充足或服務端一定允許。請按服務端返回的錯誤碼和原因提示使用者。
