直播相关——声网rtc SDK

这篇具有很好参考价值的文章主要介绍了直播相关——声网rtc SDK。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

声网 SDK项目集成与api使用整理

遥想约4年前,也自行调研过,虽然最终没有在实际项目中落地。 声网Android端集成与一对一音视频功能实现
现在,终于要开始在项目中正式落地了,而声网也从原来的v3.x升级到了v4.x版本了。根据官网介绍,两大版本间改动还是比较大的。本次集成落地,会直接用v4.x版本。
迁移指南

demo

示例项目 API-Examples
跑通 API 示例项目

生成token

进来这个地址
点击总览这里:点击:临时Token生成器生成。(24小时有效期)

水晶球

点击旁边的水晶球,进入水晶球页面,可以查看频道列表
点击对应频道,可以进入其通话详情。可以看到对应用户的uid等信息

集成

发版说明
/app/build.gradle

//声网
    dependencies {
       ...
       // x.y.z 替换为具体的 SDK 版本号,如:4.0.0 或 4.1.0-1
       implementation 'io.agora.rtc:full-sdk:x.y.z'
    }
   //implementation 'io.agora.rtc:agora-special-full:4.1.1.26'

这里的集成,可能会存在一些问题。
比如:不同版本可能会有些api用不了;比如说旧版本有些功能有些bug,所以还是使用最新的推荐版本稳妥。

混淆

/app/proguard-rules.pro 文件

#声网
-keep class io.agora.**{*;}

权限

/app/src/main/AndroidManifest.xml

<!--必要权限-->
<uses-permission android:name="android.permission.INTERNET"/>

<!--可选权限-->
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<!-- 对于 Android 12.0 及以上且集成 v4.1.0 以下 SDK 的设备,还需要添加以下权限 -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
<!-- 对于 Android 12.0 及以上设备,还需要添加以下权限 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>

tip:这里有个需要特别注意的点。如果当前项目中目标版本不是Android 12.0且不是集成 v4.1.0 以下 SDK 的设备。不能加入最后的三个权限。否则部分机型会有闪退问题。目前验证是有一部华为手机鸿蒙4.0的会闪退。
参考链接:快速开始-实现音视频互动

基本流程

创建 RtcEngineConfig 对象,并进行配置。

// 先初始化相关
try {
    //创建 RtcEngineConfig 对象,并进行配置
    initRtcEngineConfig()
} catch (e: Exception) {
    throw RuntimeException("Check the error.")
}


private fun initRtcEngineConfig() {
        // 创建 RtcEngineConfig 对象,并进行配置
        val config = RtcEngineConfig()
        config.mContext = baseContext
        config.mAppId = ""
        config.mEventHandler = mRtcEventHandler
        // 创建并初始化 RtcEngine
        mRtcEngine = RtcEngine.create(config)
    }

启用视频模块

private fun startVideo() {
   mRtcEngine?.apply {
            // 启用视频模块
            this.enableVideo()
            // 开启本地预览
            this.startPreview()
            // 创建一个 SurfaceView 对象,并将其作为 FrameLayout 的子对象
            val container: FrameLayout = findViewById(R.id.local_video_view_container)
            container.removeAllViews()
            container.addView(surfaceView)
            // 将 SurfaceView 对象传入声网实时互动 SDK,设置本地视图
            this.setupLocalVideo(VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_HIDDEN, 0))
   }
}

获取token,并且处理token过期问题

 private val mRtcEventHandler: IRtcEngineEventHandler = object : IRtcEngineEventHandler() {
        //token监听
        override fun onTokenPrivilegeWillExpire(token: String?) {
            super.onTokenPrivilegeWillExpire(token)
            needUpdateToken = true
            mPresenter.getLiveToken()
        }

        override fun onRequestToken() {
            super.onRequestToken()
            needUpdateToken = true
            mPresenter.getLiveToken()
        }
}
//处理token过期问题
if (needUpdateToken) {
    mRtcEngine?.renewToken(mPresenter.roomToken?.token.orEmpty())
    return
}

获取直播间配置参数

其中,不同分辨率和帧率下适配的码率可以看这个文档:

//获取直播间配置参数
mRtcEngine?.queryDeviceScore()?.let {
    mPresenter.getLiveConfig(it)
}
override fun getLiveConfig() {
    mPresenter.liveRoomConfig?.definition_high?.let {
        setVideoEncoderConfiguration(it)
    }
}
private fun setVideoEncoderConfiguration(configuration: LiveRoomDefinitionMedium) {
    if (renderMode != configuration.render_mode) {
        mRtcEngine?.setupLocalVideo(VideoCanvas(surfaceView, configuration.render_mode, 0))
        renderMode = configuration.render_mode
    }

    videoEncoderConfiguration.bitrate = configuration.bitrate
    videoEncoderConfiguration.frameRate = configuration.frame_rate //帧率
    videoEncoderConfiguration.mirrorMode = configuration.getMirrorMode()
    videoEncoderConfiguration.dimensions = configuration.getDimensions() //分辨率
    videoEncoderConfiguration.orientationMode = configuration.getOrientationMode()//自适应模式
    val res = mRtcEngine?.setVideoEncoderConfiguration(videoEncoderConfiguration)
}

加入频道并发布音视频流

如果是要为极速直播,则需要多设置:将 options 参数设置为 AUDIENCE_LATENCY_LEVEL_LOW_LATENCY(低延时)。

//加入频道并发布音视频流
private fun initChannelMediaOptions() {
    mPresenter.roomToken?.let {
        // 创建 ChannelMediaOptions 对象,并进行配置
        val options = ChannelMediaOptions()
        options.clientRoleType =  if (isFromControl) Constants.CLIENT_ROLE_AUDIENCE else Constants.CLIENT_ROLE_BROADCASTER
        options.channelProfile = Constants.CHANNEL_PROFILE_LIVE_BROADCASTING
        val res = mRtcEngine?.joinChannel(
            it.token,
            liveRoomBean.room_id,
            if (isFromControl) it.audience_uid.toIntDefault else it.live_uid.toIntDefault,
            options
        )

        if(res == 0){
            isConnectionLost = false
            if(isFromControl.not()){
                mPresenter.startPushStream()
            }

        }
    } ?: run {
        toast("直播地址为空!!")
    }
}

观看端

如果是设置观看端的话,则可以使用setupRemoteVideo。

离开页面的时候,需要留意关闭预览

 mRtcEngine?.stopPreview()
mRtcEngine?.leaveChannel()

一些功能使用和踩坑记录

处理截图问题

需要留意的是,不能直接在takeSnapshot这里拿到路径就开始操作。而应该到回调onSnapshotTaken中处理。
处理的过程需要留意耗时的操作要放到子线程去执行。

 private fun takeSnapshot(fileName: String = "${System.currentTimeMillis()}.jpg") {
    val uid = if(isFromControl) mPresenter.roomToken?.live_uid.toIntDefault else 0
    val filePath: String = SaveUtils.mkdir("live") +  File.separator + fileName
    val ret: Int? = mRtcEngine?.takeSnapshot(uid, filePath)
}

tip:这里遇到一个声网的bug,在使用远端用户进行截图的时候,能够正常返回图片资源。但是如果使用主播端,则会发现有延迟问题。
通过排查定位,发现这种延迟不是时间上的。而是会返回上一次截图的资源过来。目前已同步给声网,声网表示已跟进这个bug。
但是,我们还需要解决。所以首先,这边是考虑自己实现截图。简易代码如下:

 fun takeScreen(
        view: View,
        path: String?,
    ){
        val bitmap = Bitmap.createBitmap(view.width, view.height, Bitmap.Config.ARGB_8888)
        val canvas = Canvas(bitmap)
        view.draw(canvas)
        saveBitmap(bitmap, path)
    }

    private fun saveBitmap(
        bitmap: Bitmap,
        path: String? = null,
    ){
        try {
            val imageFile = File(path)
            val fos = FileOutputStream(imageFile)
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos)
            fos.flush()
            fos.close()
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }

通过验证,SurfaceView这样子截图是会失败的,截取到数据是0size。于是改成传入其包裹的容器之后,验证发现SurfaceView部分是黑屏。
当然也不能直接截全屏,因为不符合业务需求;也不能使用其他方式如TextureView替代SurfaceView。因为声网是通过SurfaceView来作为视图组件的。
而SurfaceView 是用于绘制图形的视图组件,它通常不会保存绘制的内容,而是直接将内容显示在屏幕上。具体来说,SurfaceView 的绘制是由 SurfaceFlinger 系统服务管理的,
它将 SurfaceView 的内容绘制到屏幕上的一个独立的 Surface 上。这个过程是在底层硬件加速的情况下进行的,绘制的内容并不会保存在普通的 Bitmap 中,
因此无法直接通过传统的方法获取 SurfaceView 的截图。这边不过多对SurfaceView做详解。

SurfaceView采用双缓存机制,SurfaceView在更新视图时用到了两张 Canvas,一张 frontCanvas 和一张 backCanvas ,每次实际显示的是 frontCanvas ,backCanvas 存储的是上一次更改前的视图。当你在播放这一帧的时候,它已经提前帮你加载好后面一帧了,所以播放起视频很流畅。当使用lockCanvas() 获取画布时,得到的实际上是backCanvas 而不是正在显示的 frontCanvas ,之后你在获取到的 backCanvas 上绘制新视图,
再 unlockCanvasAndPost(canvas)此视图,那么上传的这张 canvas 将替换原来的 frontCanvas 作为新的frontCanvas ,原来的 frontCanvas 将切换到后台作为 backCanvas 。例如,如果你已经先后两次绘制了视图A和B,那么你再调用 lockCanvas() 获取视图,获得的将是A而不是正在显示的B,之后你将重绘的 A 视图上传,那么 A 将取代 B 作为新的 frontCanvas 显示在SurfaceView 上,原来的B则转换为backCanvas。相当与多个线程,交替解析和渲染每一帧视频数据
引用 https://www.jianshu.com/p/a2a235bee59e
普通View onDraw 内容是静态的,不调invalidate() 它是不会发生变化,你可以拿到里面的Bitmap;但是SurfaceView不同,无法拿到它back buffer里面的Bitmap。

回到解决问题本身,既然没办法直接通过对SurfaceView截图。还是从声网的api入手。最后验证通过截图两次取第二次的方式可以解决该问题。
但是还需要注意的是,不能简单粗暴直接调用两次api。否则api还是返回异常。而是在调用第一次之后,在onSnapshotTaken再判断处理调起第二次。

设置清晰度

在设置清晰度的时候,需要先得知当前设备的设备评分等级。使用的api是:queryDeviceScore。然后再根据分数,得到适合配置进行设置。
在高清或超高清视频场景下,可以先调用该方法查询设备的等级评分。如果返回的评分较低(比如低于 60),则需要适当调低视频分辨率,以避免影响视频体验。

 private fun setVideoEncoderConfiguration(configuration: LiveRoomDefinitionMedium) {
    videoEncoderConfiguration.bitrate = configuration.bitrate
    videoEncoderConfiguration.frameRate = configuration.frame_rate //帧率
    videoEncoderConfiguration.mirrorMode = configuration.getMirrorMode()
    videoEncoderConfiguration.dimensions = configuration.getDimensions() //分辨率
    videoEncoderConfiguration.orientationMode = configuration.getOrientationMode()//自适应模式
    val res = mRtcEngine?.setVideoEncoderConfiguration(videoEncoderConfiguration)
}

token失效问题

不仅在加入频道的时候需要token,直播过程也会一直监测token的时效。因此还需要监听。声网提供了两个api:

  • onTokenPrivilegeWillExpire
  • onRequestToken。
    需要在监听到token过期或即将过期的时候,重新拿到新的token,并通过renewToken重新赋值。

对焦问题

声网提供了相关对焦的功能,包括人脸自动对焦和手动对焦功能。

  • isCameraFocusSupported 检测设备是否支持手动对焦功能
  • isCameraAutoFocusFaceModeSupported 检测设备是否支持人脸对焦功能
  • setCameraFocusPositionInPreview 设置手动对焦位置,并触发对焦
  • setCameraAutoFocusFaceModeEnabled 设置是否开启人脸对焦功能
    经过验证,发现人脸对焦在前置摄像的时候会检测不支持。因此联系声网,得到反馈是就算开启了人脸对焦,也会比较损耗性能。
    再加上经过多次验证发现,再切换镜头的时候立即调用也偶现失败。结合业务大多是开启前置,因此只接入手动对焦功能。
    而手动对焦功能,发现相比腾讯的手动对焦,声网的手动对焦感官体验上只会晃动一下,因此最好还是像腾讯的一样加多个动效。
    目前初步实现如下,感兴趣可以看看,也可以直接跳过这趴:
surfaceView.setOnTouchListener { view, event ->
    when (event.action) {
        MotionEvent.ACTION_DOWN -> {
            val x = event.x
            val y = event.y
            // 在这里处理点击事件,可以使用 x 和 y 坐标执行相应操作
            // 检测当前设备是否支持手动对焦并设置。
            if (isCameraFocusSupported) {
                // 假设在屏幕(50,100)的位置对焦。
               val res1 =  setCameraFocusPositionInPreview(x, y)
               if(res1 == 0){
                   val borderAnimationView = BorderAnimationView(this@LivePlayerActivityV2)
                   local_video_view_container.addView(borderAnimationView)

                   borderAnimationView.showAnimation(x, y)

                   Handler(Looper.getMainLooper()).postDelayed({
                       local_video_view_container.removeView(borderAnimationView)
                   }, 500) //850毫秒后执行
               }
            }

            true
        }
        else -> false
    }

}

BorderAnimationView则是一个直播对焦边框动画View,这边处理的方式:通过绘制的方式画出对应区域内的一个白色边框。然后开启缩放动画效果,最后消失。
不多说,初步代码如下:

class BorderAnimationView(context: Context) : View(context) {
    private var x = 0f
    private var y = 0f
    private var scale = 1f
    private var paint = Paint().apply {
        color = Color.WHITE
        style = Paint.Style.STROKE
        strokeWidth = 3f
    }

    fun showAnimation(x: Float, y: Float) {
        this.x = x
        this.y = y
        scale = 1f
        invalidate() // 请求重绘
        startScaleAnimation()
    }

    private fun startScaleAnimation() {
        val scaleTo = 1.25f
        val scaleBack = 1f

        val scaleAnimation = ValueAnimator.ofFloat(scale, scaleTo)
        scaleAnimation.addUpdateListener { valueAnimator ->
            scale = valueAnimator.animatedValue as Float
            invalidate()
        }
        scaleAnimation.duration = 250 // 0.25秒
        scaleAnimation.interpolator = AccelerateDecelerateInterpolator()

        val scaleBackAnimation = ValueAnimator.ofFloat(scaleTo, scaleBack)
        scaleBackAnimation.addUpdateListener { valueAnimator ->
            scale = valueAnimator.animatedValue as Float
            invalidate()
        }
        scaleBackAnimation.duration = 350 // 0.35秒
        scaleBackAnimation.interpolator = AccelerateDecelerateInterpolator()

        scaleAnimation.addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationEnd(animation: Animator?) {
                scaleBackAnimation.start()
            }
        })

        scaleAnimation.start()
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        val scaledSize = 80.dp * scale
        val halfScaledSize = scaledSize / 2
        canvas.drawRect(x - halfScaledSize, y - halfScaledSize, x + halfScaledSize, y + halfScaledSize, paint) // 绘制带有白色边框的矩形
    }
}

网络监听

直播过程避免网络波动,因此需要监听网络做出必要的交互。声网提供的api是onNetworkQuality。
需要注意的是,要判断是主播端还是观看端。
如果是主播端,则应该拿上行网络质量txQuality进行判断;如果是观看端,则应该用下行网络质量rxQuality。
不足的地方是,只能拿到网络质量状态的枚举,而没能拿到具体网络速率等数值。文章来源地址https://www.toymoban.com/news/detail-838739.html

其他

  • 美颜美白:这个主要是业务逻辑比较多,实际核心代码就是调用setBeautyEffectOptions进行设置。声网还支持了更多的美颜面板设置。
mRtcEngine?.setBeautyEffectOptions(true, options)
  • 告警通知服务:比如视频卡顿率在一定周期内连续大于某个阈值。告警通知

到了这里,关于直播相关——声网rtc SDK的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 保姆级教程!基于声网 Web SDK实现音视频通话及屏幕共享

    本篇文章主要给小伙伴们分享如何使用声网 SDK 实现 Web 端音视频通话及屏幕共享功能,其中也会涵盖在实践过程中遇到的一些问题,以此记录防止小伙伴们踩坑,同时也希望通过从 0 到 1 实战的分享,能够帮助更多的小伙伴。

    2024年02月16日
    浏览(64)
  • WebRTC音视频通话-RTC直播本地视频及相册视频文件

    WebRTC音视频通话-RTC直播本地视频及相册视频文件 WebRTC音视频通话-RTC直播本地视频文件效果图如下 WebRTC音视频通话-RTC直播本地视频文件时候,用到了AVPlayer、CADisplayLink。 AVPlayer是什么? AVPlayer是基于AVFoundation框架的一个类,很接近底层,灵活性强,可以自定义视频播放样式

    2024年02月13日
    浏览(51)
  • 「专题速递」数据驱动赋能、赛事直播优化、RTC技术、低延时传输引擎、多媒体处理框架、GPU加速...

    点击文末阅读原文, 免费报名【抖音背后的体验增长实战揭秘】专场 随着全行业视频化的演进,营销、知识、商业和空间的交互体验正在被重塑。这种变化不仅仅是一种抽象的趋势,更是关系到用户留存和业务增长的关键因素。面对这样的挑战,一个关键的问题摆在我们面

    2024年02月06日
    浏览(49)
  • 探索未来:直播实时美颜SDK在增强现实(AR)直播中的前景

    在AR直播中,观众可以与虚拟元素实时互动,为用户带来更加丰富、沉浸式的体验。那么,直播美颜SDK在AR中有哪些应用呢?下文小编将于大家一同探讨美颜SDK与AR有哪些关联。 一、AR直播与直播实时美颜SDK的结合 增强现实技术在直播中的应用,让用户不仅可以观看主播的实时

    2024年02月13日
    浏览(48)
  • 主播直播美颜SDK:性能优化策略

    当下,主播直播美颜SDK成为了越来越多主播的利器。这些SDK可以实时美化主播的外貌,提高视觉吸引力,但同时也需要处理大量的图像数据。因此,性能优化成为了不可或缺的一环。本文将探讨主播直播美颜SDK的性能优化策略,以确保高质量的实时美颜效果。 一、了解性能瓶

    2024年02月06日
    浏览(43)
  • 美狐讲堂:视频用直播用SDK盘点

    1、推流:阿里云直播、七牛云等 阿里云直播是由阿里集团推出的SDK,免费使用,但美颜效果一直都有问题,如果不满意的话,解决策略是接入另一个三方的美颜SDK。 七牛云效果还行,能满足市面上的大部分功能,就连麦方面的话,七牛云主体是客户端合流,对网络、设备的

    2024年01月17日
    浏览(38)
  • 深入解析:如何打造高效的直播视频美颜SDK

    在当今数字化时代,视频直播已经成为人们交流、娱乐和信息传递的重要方式。然而,许多人在直播时都希望能够呈现出最佳的外观,这就需要高效的直播视频美颜技术。本文将深入解析如何打造高效的直播视频美颜SDK,以实现令人满意的视觉效果。 一、理解美颜SDK的核心原

    2024年02月09日
    浏览(45)
  • 准备选型直播SDK产品,ChatGPT竟然这么说...

    近两年即时通讯/直播产品炙手可热,市场上针对ToB的产品日益增多,企业该如何去选型呢?本文分享了笔者对于直播产品的思考,将从直播SDK实例功能特性、常见业务场景、注意事项及最佳实践等方面介绍如何进行实例选型,旨在帮助您了解应如何结合实际业务场景选购音视

    2024年02月02日
    浏览(38)
  • 【正点原子STM32】RTC实时时钟(RTC方案、BCD码、时间戳、RTC相关寄存器和HAL库驱动、RTC基本配置步骤、RTC基本驱动步骤、时间设置和读取、RTC闹钟配置和RTC周期性自动唤醒配置)

    一、RTC简介 二、STM32 RTC框图介绍 2.1、STM32 F1 RTC结构框图 2.2、STM32 F4 / F7 / H7 RTC结构框图 三、RTC相关寄存器介绍 3.1、RTC基本配置步骤 3.2、RTC相关寄存器(F1) 3.3、RTC相关寄存器(F4 / F7 / H7) 四、RTC相关HAL库驱动介绍 4.1、RTC相关HAL库驱动(F1) 4.2、RTC相关HAL库驱动(F4 / F7 /

    2024年03月27日
    浏览(71)
  • 实时美颜的背后:视频直播美颜SDK的算法与原理

    美颜技术的应用范围已经广泛扩展,从自拍照片到视频直播,都可以看到它的踪迹。然而,视频直播的实时性要求比静态图像高得多。要实现实时美颜,必须克服许多技术挑战。这就是视频直播美颜SDK的用武之地。 一、实时美颜的挑战 实时美颜涉及到几个关键挑战,包括:

    2024年02月09日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包