视频通话

更新时间:2024-04-26 08:49:27下载pdf

IPC SDK 提供双向视频通话能力,由 音视频功能–本地视频模块 和 通话管理模块构成。可用于实现带屏 IPC 和中控屏等设备双向视频通话功能。

流程说明

双向视频通话功能包括 App 侧主动呼叫接收设备呼入 两部分。具体流程如下:

  1. 判断设备是否支持双向视频通话能力,支持则继续。
  2. 初始化双向视频通话 SDK,注册消息模块监听。
  3. SDK 发起视频通话/接收设备呼入,同时建立 P2P,打开实时视频。
  4. 通话管理,状态监听同步。
  5. 通话结束退出。
  6. 注销。

是否支持双向视频通话

判断设备是否支持双向视频通话高级能力。

接口说明

 fun fetchSupportVideoCall(devId: String, callback: IThingResultCallback<Boolean>?)

参数说明

参数 说明
devId 设备 ID
callback 方法回调,返回 Boolean 值,true 表示支持

示例代码

ThingIPCSdk.getVideoCall()?.fetchSupportVideoCall(mDevId, object : IThingResultCallback<Boolean> {
                override fun onSuccess(result: Boolean?) {
                    TODO("Not yet implemented")
                }

                override fun onError(errorCode: String?, errorMessage: String?) {
                    TODO("Not yet implemented")
                }
            })

初始化视频通话模块

初始化注册视频通话模块,用于接收处理呼叫通话的各种状态。

建议放在登录后执行。在调用 SDK 功能前,模块必现完成初始化。

接口说明

fun registerCallModuleProvider(category: String, interfaceProvider: ICallInterfaceProvider )

参数说明

参数 说明
category 注册模块标识,用于匹配需要处理的视频通话消息。目前,仅支持 screen_ipc
interfaceProvider 视频通话 SDK 回调接口 ICallInterfaceProvider

ICallInterfaceProvider

当收到设备呼入或 App 侧主动呼出成功后,会回调执行 launchUI 方法并携带 ThingCall 对象。

系统推送类消息不会主动回调该方法。接收到系统推送消息后,需要调用 receiveCallMessage 方法把 ThingCall 传入 SDK 进行状态检查、同步管理。当检查状态正常时,会回调执行 launchUI 方法。

fun launchUI(call: ThingCall)

ThingCall 说明

视频通话模型,包括通话相关方信息和通话状态。

参数 说明
appDeviceId 手机识别信息已加密
callType 呼叫模式 ThingCallType 枚举值,App 侧取 oneToOne(1)
curId 呼叫方 ID
targetId 接收方 ID
sessionId 呼叫会话 ID
timeout 超时时间
extra 扩展参数 Map 类型,转换 JSON 格式:{"bizType":"screen_ipc","channelType":2,"category":"sp_dpsxj"}
targetState 呼叫状态枚举 ThingTargetState
outgoing App SDK 侧是否是主叫方

ThingTargetState 说明

呼叫状态枚举值。

enum class ThingTargetState(
    val value: Int
) {
    /** 未知 */
    UNKNOWN(0),
    // 以下状态为主叫状态
    /** 发起通话中 */
    INITIATING(1001),
    /** 接听 */
    ANSWER(1002),
    /** 拒接 */
    REJECT(1003),

    // 以下状态为被叫状态
    /** 响铃中 */
    RINGING(2001),
    /** 忙线 */
    BUSY(2002),
    /** 对方收到 answer 消息的应答 */
    ALREADY_ANSWERED(2003),
    /** 有人已经接听 */
    OTHER_ANSWERED(2004),
    /** 对方取消 */
    CANCEL(2005),
    /** 有人已经拒接 */
    ALREADY_REJECTED(2006),

    // 以下状态为通用状态
    /** 通话中 */
    CALLING(3001),
    /** 挂断 */
    HANG_UP(3002),
    /** 通话结束 */
    STOP(3003),
    /** 通话异常 */
    ERROR(3004),
    /** 通话超时 */
    TIMEOUT(3005),
}

示例代码

ThingIPCSdk.getVideoCall()?.registerCallModuleProvider("screen_ipc", ScreenCameraProvider())

...

class ScreenCameraProvider : ICallInterfaceProvider {

    override fun launchUI(thingCall: ThingCall) {
       // start Activity
    }
}

注册消息模块

注册视频呼叫消息处理模块,用于监听和处理 MQ 视频消息。建议在登录后先调用 registerCallModuleProvider 初始化注册视频通话模块,之后调用 registerMessageHandler() 立即注册消息模块。

接口说明

fun registerMessageHandler()

注销消息模块

注销视频呼叫消息处理模块,用于释放监听器及其他资源。建议在退出登录时进行。

接口说明

fun unRegisterMessageHandler()

主动发起通话

IPC SDK 发起视频通话。

接口说明

fun launchCall(
        targetId: String,
        timeout: Long,
        extra: Map<String, Any>,
        success: SuccessCallback,
        failure: FailureCallback,
    )

参数说明

参数 说明
targetId 被叫方 ID,一般指设备 ID
timeout 超时时间
extra 扩展参数 Map 类型,转换 JSON 格式:{"bizType":"screen_ipc","channelType":2,"category":"sp_dpsxj","keepConnect":false}
success 成功回调
failure 失败回调,返回 ThingCallError

ThingCallError

enum class ThingCallError(
    val value: Int
) {
    /** 通用错误 */
    GENERAL(-1),
    /** 通话被拒接 (对方正忙) */
    REJECT(1001),
    /** 对方占线 (对方正忙) */
    BUSY(1002),
    /** 对方超时未接听 (对方未接听) */
    NOT_ANSWER(1003),
    /** 通话被其他人拒接(通话已被拒接) */
    ALREADY_REJECTED(2001),
    /** 通话被其他人接听 (通话已被接听) */
    ALREADY_ANSWERED(2002),
    /** 通话超时 (对方未接听) */
    TIMEOUT(3001),
    /** 通话流建立失败 (通话异常) */
    CONNECT_FAIL(3002),
    /** 通话流断开 (通话异常) */
    DISCONNECT(3003),
    /** 通话异常 (通话异常) */
    STOP(3004),
}

示例代码

ThingIPCSdk.getVideoCall()?.launchCall(devId, 30L, extra,
        object : SuccessCallback {
            override fun invoke() {
            }
        }, object : FailureCallback {
            override fun invoke(error: ThingCallError) {
            }
        })

接收呼入推送消息

推送其他渠道呼入的通话信息给视频通话 SDK,统一进行状态管理,包括检查通话状态是否过期、已被其他人接听、繁忙等。

  • 如果出现异常状态,则返回具体的错误状态 ThingCallError
  • 如果检查状态正常,则回调执行 launchUI 方法。

接口说明

 fun receiveCallMessage(
        call: ThingCall,
        success: SuccessCallback,
        failure: FailureCallback,
    )

参数说明

参数 说明
call 视频通话模型
success 成功回调
failure 失败回调,返回 ThingCallError

示例代码

 thingCall?.let { call ->
                    L.d(TAG, "receive receiveCall")
                    if (callEvent == ThingCallEvent.CALL) {
                        ThingIPCSdk.getVideoCall()?.receiveCallMessage(
                            call,
                            {   //成功 },
                            {
                              // 失败
                            })
                    }

通话管理

ICallInterfaceProvider#launchUI(call: ThingCall) 调用后打开通话界面 UI 成功后,需要调用此 launchUISuccess 方法通知 SDK,SDK 会将状态同步到云端并进行状态管理。SDK 限制同时仅一个会话存在。

接口说明

fun launchUISuccess(call: ThingCall, callInterface: ICallInterface?)

参数说明

参数 说明
call 视频通话模型
callInterface 注册监听 ICallInterface,与 SDK 双向绑定通话过程中的操作

ICallInterface

管理通话状态。

interface ICallInterface {

    var call: ThingCall?

    var listener: ICallInterfaceListener?

    /**
     * 收到视频呼叫(mq)消息的回调,注意如果已经有呼叫在接听中,则不会回调此方法
     */
    fun callStart(call: ThingCall)

    /**
     * 收到视频呼叫(mq)消息的回调,已经有通话在,直接拒绝回调
     */
    fun callCancel(call: ThingCall)

    /**
     * 通话状态更新 [ThingCall.targetState] 字段标识通话对象的状态
     */
    fun callUpdate(call: ThingCall)

    /**
     * 超时,详情参考 [Timer]
     */
    fun timeout()
}

ICallInterfaceListener

视频通话操作并同步 SDK,SDK 进行会话状态管理。

interface ICallInterfaceListener {
 /**
     * 视频呼叫响铃
     */
    fun onRing()
    /**
     * 视频呼叫挂断
     */
    fun hangupClick()
    /**
     * 视频呼叫接听
     */
    fun acceptClick()
    fun onStartConnect()
    /**
     * 视频呼叫连接状态,异常状态(例如 P2P 异常断开)设置为 false,
     */
    fun onConnect(result: Boolean)
    fun onDisconnect()
    fun onException()
    /**
     * 视频呼叫退出
     */
    fun onViewDestroy()
}

示例代码

class VideoCallFragment : BaseFragment(), ICallInterface {

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?,
    ): View {
        ...
        var call = arguments?.getParcelable(BUNDLE_CALL_KEY)
        call?.let {
            ThingIPCSdk.getVideoCall()?.launchUISuccess(it, this)
        }
         ...
        return inflater.inflate(R.layout.xxx,container,false)
    }

    override fun onDestroyView() {
        ...
        super.onDestroyView()
    }

    override var call: ThingCall? = null
    override var listener: ICallInterfaceListener? = null
        set(value) {
            L.d(TAG, "setInterfaceListener $value")
        }

    override fun callStart(call: ThingCall) {

    }

    override fun callCancel(call: ThingCall) {
    }

    override fun callUpdate(call: ThingCall) {
        ...
        when (call.targetState) {
            ThingTargetState.INITIATING -> {
            }
            ThingTargetState.RINGING -> {
            }
            ThingTargetState.CALLING -> {
            }
            ThingTargetState.ANSWER,
            ThingTargetState.ALREADY_ANSWERED,
            -> {
            }
            ThingTargetState.CANCEL -> {
                showToast(R.string.call_cancel_error)
            }
            ThingTargetState.REJECT -> {
                showToast(R.string.call_busy)
            }
            ThingTargetState.OTHER_ANSWERED -> {
                showToast(R.string.call_already_answered)
            }
            ThingTargetState.ALREADY_REJECTED -> {
                showToast(R.string.call_already_rejected)
            }
            ThingTargetState.BUSY -> {
                showToast(R.string.call_busy)
            }
            ThingTargetState.HANG_UP,
            -> {
                showToast(R.string.call_call_finish)
            }
            ThingTargetState.ERROR,
            ThingTargetState.STOP,
            -> {
                showToast(R.string.call_execption)
            }
            ThingTargetState.TIMEOUT -> {
                showToast(R.string.call_timeout)
            }
            else -> {}
        }
    }

    override fun timeout() {
        L.w(TAG, "timeout called")
        ...
    }

}

是否有视频通话

检查 SDK 是否正进行视频通话,SDK 限制同时仅一个会话存在。如果正在通话中,会返回 true不允许再建立新的视频通话

接口说明

fun isCalling(): Boolean