本文为声网 RTE 开发者社区作者投稿,作者为@arige

指标

1. 制订指标

无妨大家想一下这个场景:

你走进一个咖啡厅,看到了一个美女或者帅哥,想要一个微信号,不便后续倒退。

那咱们要怎么做呢?

走到对方跟前,小声对他说:“你好,你长的很像我的前女友(前男友),能够加下你的微信吗?”。

对方有可能悄声的说,“我扫你”。

你这个时候你就须要把你的二维码展现给他。

当你们恋爱胜利,求婚的时候,可能要找一个更加浪漫的环境,并且你们的对话心愿给更多人看到、听到。

通过这个下面场景的设想,咱们能够简略的确定一些根本的因素

  1. 能够更改的场景 (咖啡厅和求婚现场)
  2. 自主塑造形象性能(毕竟外貌是一见倾心的原点)
  3. 单聊 (要微信号不能一次要一群人得呀。不然可能被当成流氓给打得哟)
  4. 文件共享 (把本人得二维码展现给对方,让对方加好友)
  5. 群聊、群视频 (把求婚现场给其余用户看)

2. 拆解指标

为了满足下面提到得要求,咱们须要以下性能:

  1. 反对unity的不便接入。毕竟unity是一个十分好的3D引擎,如果能够不便接入得话,在后续得场景创立和人物发明上都能够有更大的扩大空间
  2. 1 vs 1的视频,或者 1 vs 多的直播模式。能够满足单聊和群聊的需要
  3. 同步本地播放的本地视频或者远端视频给其余用户。能够满足共享二维码的需要。

3. 成果预览

如果要残缺的实现一个残缺的我的项目会破费比拟多的工夫,而我发现目前声网的 Demo 会提供简略的人物模型和素材,然而他们开放度较高,开发者能够依据须要应用本人定制化的模型素材,为了实现上述提到的需要,我只做了一些渺小的批改,就满足了咱们的需要。本次次要看下成果,为后续在生产环境中落地做一些技术上的储备。

以下是在demo上调整后显示进去的成果。


这是用unity来实现的一个咖啡厅的样子


这是一个服装店,咱们能够给人物进行换装,这个也是由unity来实现的。

以上两个的接入都十分的不便,咱们能够很好的对接unity,如果需要的话,后续有本人的unity场景也能够疾速接入。


这个是我本人测试的1 vs 1的视频测试成果

这个是我本人测试的将本地视频分享给对方的一个成果

设想一下,是不是能够和你的对象一起看剧了呢?

简略实现

以上成果都是基于声网的sdk来实现的,如果你也想进行尝试或者应用,能够持续查看我的接入过程和两头遇到的问题以及解决方案。

1. 账号筹备

咱们既然应用了声网的sdk,那注册一个声网的账号做一些声网的账号配置也很正当吧。

  1. 注册账号
  2. 实现实名
  3. 创立我的项目

  1. 配置我的项目

而后进入具体配置

生成token,并将appid、证书、token复制保留。
留神!!!这里很重要,肯定要看认真,我的项目中会应用到!

至此,账号的筹备曾经实现了。

2. 配置我的项目

  1. demo源码
  2. 通过声网官网客服,申请元宇宙 SDK、Unity工程文件、开发指南,同时申请开明应用权限,详情可拜访 shengwang.cn
  3. 将sdk解压并配置到我的项目中 肯定要留神目录,如果本人的我的项目中不存在以后的目录要本人创立

  1. 配置id个别状况下,这个文件是不会上传到近程仓库的,写到这里也次要是平安思考。将在后盾中申请的appid、证书,复制后粘贴到/Android/local.properties外面,如下:
  2. 配置channel 将在后盾生成token的时候,填写的channel给写到类中,如下
  3. 配置我的项目权限
 <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 及以上设施,还须要增加如下权限: --> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"  />

留神:

Manifest.permission.RECORD_AUDIO,Manifest.permission.CAMERA

须要动静申请权限,否则无奈失常实现视频性能。

sdk自身是不会去申请权限的,所以须要咱们本人在适合的地位帮sdk申请好权限。

  1. 混同配置


咖啡厅

做形象


服装店

这里是间接应用了声网给的成果,如果本人我的项目需要的话,能够去本人去调整。

其中换装和捏脸都须要unity上的一些批改和native与unity的通信。整个能够参考换装和捏脸

3. 视频1vs1

后面曾经实现了整体我的项目的构建。并且曾经把unity内容跑起来了,那么接下来咱们看下,如果要实现 1vs1的视频要怎么解决。为了不便解决,我独自写了一个页面来解决视频1vs1,成果如下:


视频聊天

这个流程图,倡议大家多看几遍,在咱们遇到问题的时候,这个图会给咱们启发,帮忙咱们解决问题。

具体流程:

1. 创立RtcEngine对象

该对象治理了整个的视频等场景,是一个十分外围的对象。

 try {            RtcEngineConfig config = new RtcEngineConfig();            config.mContext = getBaseContext();            config.mAppId = appId;            config.mEventHandler = mRtcEventHandler;            config.mAudioScenario = Constants.AudioScenario.getValue(Constants.AudioScenario.DEFAULT);            mRtcEngine = RtcEngine.create(config);        } catch (Exception e) {            throw new RuntimeException("Check the error.");        }

2. 创立RtcEngine属性

  // 视频默认禁用,你须要调用 enableVideo 启用视频流。        mRtcEngine.enableVideo();        // 录音默认禁用,你须要调用 enableAudio 启用录音。        mRtcEngine.enableAudio();        // 开启本地视频预览。        mRtcEngine.startPreview();

3. 将本地摄像头内容显示到local_video_view_container上

FrameLayout container = findViewById(R.id.local_video_view_container);        // 创立一个 SurfaceView 对象,并将其作为 FrameLayout 的子对象。        SurfaceView surfaceView = new SurfaceView (getBaseContext());        container.addView(surfaceView);        // 将 SurfaceView 对象传入声网,以渲染本地视频。        mRtcEngine.setupLocalVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_FIT, KeyCenter.RTC_UID));

4. 设置以后的模式

   ChannelMediaOptions options = new ChannelMediaOptions();        // 将用户角色设置为 BROADCASTER。        options.clientRoleType = Constants.CLIENT_ROLE_BROADCASTER;        // 视频通话场景下,设置频道场景为 BROADCASTING。        options.channelProfile = Constants.CHANNEL_PROFILE_LIVE_BROADCASTING;

其中clientRoleType有两种,如果是CLIENT_ROLE_BROADCASTER就是能够播和收,如果是CLIENT_ROLE_AUDIENCE就只能收看,以后就成了主播模式。

5. 退出频道

 // 应用长期 Token 退出频道。        // 你须要自行指定用户 ID,并确保其在频道内的唯一性。        int res = mRtcEngine.joinChannel(token, channelName, KeyCenter.RTC_UID, options);        if (res != 0)        {            // Usually happens with invalid parameters            // Error code description can be found at:            // en: https://docs.agora.io/en/Voice/API%20Reference/java/classio_1_1agora_1_1rtc_1_1_i_rtc_engine_event_handler_1_1_error_code.html            // cn: https://docs.agora.io/cn/Voice/API%20Reference/java/classio_1_1agora_1_1rtc_1_1_i_rtc_engine_event_handler_1_1_error_code.html            Log.e("video","join err:"+RtcEngine.getErrorDescription(Math.abs(res)));        }

joinChannel办法有返回值,能够看到咱们退出频道是否胜利了,如果不胜利的话,咱们能够看下谬误起因,并对照解决;如果胜利了,就能够察看IRtcEngineEventHandler对象的回调办法,重点关注下 onError(int err) 和onJoinChannelSuccess(String channel, int uid, int elapsed) 如果收到 onJoinChannelSuccess办法的回调,咱们就能够关注 onUserJoined(int uid, int elapsed) 办法,咱们能够在这个办法里开始显示远端内容。

6. 显示远端内容

   @Override        // 监听频道内的远端主播,获取主播的 uid 信息。        public void onUserJoined(int uid, int elapsed) {            Log.e(TAG, "onUserJoined->" + uid);            runOnUiThread(new Runnable() {                @Override                public void run() {                    // 从 onUserJoined 回调获取 uid 后,调用 setupRemoteVideo,设置远端视频视图。                    setupRemoteVideo(uid);                }            });        }  private void setupRemoteVideo(int uid) {        FrameLayout container = findViewById(R.id.remote_video_view_container);        SurfaceView surfaceView = new SurfaceView (getBaseContext());        surfaceView.setZOrderMediaOverlay(true);        container.addView(surfaceView);        mRtcEngine.setupRemoteVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_FIT, uid));    }

最终,远端的视频会显示在 remote_video_view_container 上。

4. 将本地播放的视频显示给远端用户


同步本地播放给远端

将本地视频怎么同步给远端的用户呢?其实从实质上来讲,将本地摄像头和将本地播放的视频给远端用户看,对远端用户都是一样的,不一样的是本地用户给远端用户的数据源是哪个。一个是摄像头,一个是播放器。

  1. 设置本地video的时候做下批改
 FrameLayout container = findViewById(R.id.local_video_view_container);        // 创立一个 SurfaceView 对象,并将其作为 FrameLayout 的子对象。        SurfaceView surfaceView = new SurfaceView (getBaseContext());        container.addView(surfaceView);        // 将 SurfaceView 对象传入声网,以渲染本地视频。        VideoCanvas videoCanvas = new VideoCanvas(surfaceView, Constants.RENDER_MODE_HIDDEN, Constants.VIDEO_MIRROR_MODE_AUTO,                Constants.VIDEO_SOURCE_MEDIA_PLAYER,  mediaPlayer.getMediaPlayerId(), KeyCenter.RTC_UID);        mRtcEngine.setupLocalVideo(videoCanvas);
  1. 在int res = mRtcEngine.joinChannel(token, channelName, KeyCenter.RTC_UID, options);是0的时候,调用如下办法:
  int res = mRtcEngine.joinChannel(token, channelName, KeyCenter.RTC_UID, options);        if (res != 0)        {            // Usually happens with invalid parameters            // Error code description can be found at:            // en: https://docs.agora.io/en/Voice/API%20Reference/java/classio_1_1agora_1_1rtc_1_1_i_rtc_engine_event_handler_1_1_error_code.html            // cn: https://docs.agora.io/cn/Voice/API%20Reference/java/classio_1_1agora_1_1rtc_1_1_i_rtc_engine_event_handler_1_1_error_code.html            Log.e("video","join err:"+RtcEngine.getErrorDescription(Math.abs(res)));        }else {            mediaPlayer = mRtcEngine.createMediaPlayer();            mediaPlayer.registerPlayerObserver(this);            mediaPlayer.open(MetaChatConstants.VIDEO_URL, 0);        }

3.监听onPlayerStateChanged回调并在state是PLAYER_STATE_OPEN_COMPLETED的时候执行play办法,代码如下:

 public void onPlayerStateChanged(io.agora.mediaplayer.Constants.MediaPlayerState state, io.agora.mediaplayer.Constants.MediaPlayerError error) {        if(state == io.agora.mediaplayer.Constants.MediaPlayerState.PLAYER_STATE_OPEN_COMPLETED){            mediaPlayer.play();        }    }

至此,就实现了性能上的应用。

其它性能

除了下面提到的性能外,声网还提供了一些其余的性能,在须要的时候能够间接应用,或者大量批改就能够用的。

比如说空间音效性能,该性能基于声学原理,模仿声音在不同空间环境中的流传、反射、排汇成果。能够为用户提供游览中路人聊天声、海浪声、风声等,让用户更沉迷式体验

再比如说实时共赏影音性能。该性能能够简直无延时的实现,近程观影、听歌等性能。甚至能够实现k歌的能力。

更多的性能期待大家一起挖掘!

参考资料

  • 注册并试用每月 10000 分钟收费的声网视频SDK,体验四行代码、三十分钟疾速构建沉迷式实时互动场景
  • 下载体验声网相干 SDK & Demo