乐趣区

关于前端:在元宇宙中搭建语聊房设计思路和实现方法分享

本文为声网 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
退出移动版