美丽的草原我的家,Android 开发实践:完成17人视频l谈天使用,我好想你

自从2016年,宣扬“互联网隆冬”的论调甚嚣尘上,2017年亦有愈演愈烈之势。但连麦直播、在线抓娃娃、直播问答、长途狼人杀等类型的项目却异军突起,成了投资人的风口,创业者的蓝海和用户的必装App,而这些方向的项目都有一个一起的特色——都依靠视频通话和全互动直播技能。

现在有许多第三方渠道供给实时音视频通讯效劳,让Android、iOS开发者们不用去考虑网络延时、设备兼容等方面的问题。咱们这次将试着经过声网的SDK完结一个多人视频通话运用。

环境

声网Agora.io 蒋新瑶SDK的兼容性杰出,对硬件设备和软件体系的要求不高,开发环境和测验环境满意以下条件即可:

  • Android SDK API Level >= 16
  • Android Studio 2.0 或以上版别
  • 支撑语音和视频功用的真机
  • App 要求 Android 4.1 或以上设备

以下是我试用声网Agora.io SDK的开发环境和测验环境:

  • 开发环境
  • Windows 10 家庭中文版
  • Java Version SE 8
  • Android Studio 3.2 Canary 4

测验环境

  • Samsung Nexus (Android 4.4.2 API 19)
  • Mi Note 3 (Android 7.1.1 API 25)

集成

进程一:首要害此下载完好的SDK和官方demo

进程二:已然咱们要把声网Agora.io集成到自己的项目里,所以不用运转sample,咱们自己新建一个HelloAgora项目,留意一定要支撑C++哦。

进程三:把libs文件夹里的arm64-v8a、、armeabi-v7a以及x86文风险联系件夹复制粘贴到app module的libs里。假如有NDK开发的必要,则把libs->include文件夹里的两个.h头文件复制粘贴到适宜方位。

进程四:首要在app module的build.gradle文件的android代码块中添加如下代码:

sourceSets {
main {
jniLibs.srcDirs = ['../../../libs']
}
}

然后在app module的build.gradle文件的android->defaultConfig代码块中添加如下代码:

ndk {
abiFilters "armeabi-v7a", "x86"
}

接下来在app module的build.gradle文件的dependencies代码块中添加如下代码:

compile 'i美丽的草原我的家,Android 开发实践:完结17人视频l谈天运用,我好想你o.agora.rtc:full-sdk:2.0.0'

假如用复制粘贴jar的办法,那么此处添加如下代码:

compile fileTree(dir: '../../../libs', include: ['*.jar'])

假如有自界说NDK的必要,可以持续在app module的build.gradle文件的android代码块中添加如下代码:

externalNativeBuild {
ndkBuild {
path 'src/main/cpp/Android.mk'
}
}

然后在app module的build.gradle文件的android->defaultConfig代码块中添加如下代码:

externalNativeBuild {
ndkBuild {
arguments "NDK_APPLICATION_MK:=src/main/cpp/Application.mk"
}
}

终究sync一下,声网Agora.io的SDK就集成到项目中来了。

权限

SDK集成完毕后,为了确保SDK能正常运转,咱们需求在AndroidManisfest.xml 文件中声明以下权限:















这些权限都是Android开发进程中的常见权限,有经历的程序员都会感觉眼熟,WRITE_EXTERNAL_STORAGE等灵敏权限适配Android 6.0今后版别的问题并非本文重视要害,在此不做赘述。

混杂代码

集成SDK并声明晰权限后,就该考虑混杂的问题了,咱们需求在project的proguard-rules.pro文件里添加以下代码:

-keep class io.agora.**{*;}

经过以上进程后,咱们现已完结了声网Agora.io SDK的快速集成,迈出了走向连麦直播、在线抓娃娃、直播问答、长途狼人杀等风口的第一步。在接下来的文章里,我将持续共享APP ID鉴权、Token鉴权、一对一视频谈天、创立群聊room、分屏、窗口切换和前后摄像头切换等内容。

鉴权

APP ID鉴权

所谓APP ID,便是在 Agora创立每个项目都有的一个仅有标识。App ID 可以清晰你的项目及安排身份,并在 joinChannel 办法中作为参数,衔接到 Agora 实时网络中,完结实时通讯或直播功用。不同的App ID在Agora实时网络中的通话是彻底阻隔的;Agora 供给的频道信息、计费、办理效劳也都是依据 App ID。

请求APP ID的操作很简洁,只要在Agora官网https://dashboard.agora.io/projects右侧栏意图“项目”中点击“添加新项目”,只需输入项目名就可生成APP ID,全进程如下图所示:

找到,把“<#YOUR APP ID#>”替换为图中的马赛克里的字符串。

<#YOUR APP ID#>

以上便是APP ID鉴权的全进程。

虽然App ID鉴权在最大程度上便利了开发者运用 Agora 的效劳。但App ID 鉴权的安全性欠安,一旦有心怀叵测的人不合法获取了你的 App ID,他就可以在 Agora 供给的SDK中运用你的App ID。假如你的项目对安全性要求高,或许添加用户权限设置的话,主张选用Token鉴权。

Token鉴权

在通讯和直播场景中存在着多个人物,而每种人物又对应着一些默许权限。比如在直播场景中,主播可以发布流、订阅流、约请嘉宾;观众可以订阅流、请求连麦;办理员则可以踢人或禁言。

Toke尚仙n鉴权的进程比APP ID鉴权略微杂乱一些,在上文项目列表中检查 App ID 的当地,启用该项意图 App Certificate:

首要,点击激活项目右上方的 修改 按钮。

将你的 App Certificate 保存在效劳器端,且对任何客户端均不可见。当项意图 App Certificate 被启用后,你有必要运用 Token。例如: 在启用 App Certificate 前,你可以运用 App ID 参加频道。但启用了 App C色色归纳ertificate 后,你就有必要运用 Token 参加频道。后台如何用App Certificate生成Token本文不做赘述。

初始化Agora

RtcEngine 类包含运用程序调用的首要办法,调用 RtcEngine 的接口最好在同一个线程进行,不主张在不同的线程一起调用。

现在 Agora Native SDK 只支撑一个 RtcEngine 实例,每个运用程序仅创立一个 RtcEngine 目标 。 RtcEngine 类的一切接口函数,如无特别阐明,都是异步调用,对接口的调用主张在同一个线程进行。一切回来值为 int 型的 API,如无特别阐明,回来值 0 为调用成功,回来值小于 0 为调用失利。

IRtcEngineEventHandler接口类用于SDK向运用程序发送回调事情告诉,运用程序经过承继该接口类的办法获取 SDK 的事情告诉。

接口类的一切办法都有缺省(空)完结,运用程序可以依据需求只承继关怀的事情。在回调办法中,运用程序不该该做耗时或许调用或许会引起堵塞的 API(如 SendMessage),不然或许影响 SDK 的运转。

private RtcEngine mRtcEngine;
/**
* Tutorial Step 1
* 初始化Agora,创立 RtcEngine 目标
*/
private void initializeAgoraEngine() {
try {
mRtcEngine = RtcEngine.create(getBaseContext(), getString(R.string.agora_app_id), mRtcEventHandler);
} catch (Exception e) {
Log.e(LOG_TAG, Log.getStackTraceString(e));
throw new RuntimeException("Agora初始化失利了,检查一下是哪儿出错了\n" + Log.getStackTraceString(e));
}
}
private final IRtcEngineEventHandler mRtcEventHandler = new IRtcEngineEventHandler() {
@Override
public void onFirstRemoteVideoDecoded(final int uid, int width, int height, int elapsed) {
runOnUiThread(new Runnable() {
@Override
public void run() {
//设置远端视频显现特点
setupRemoteVideo(uid);
}
});
}
@Override
public void onUserOffline(int uid, int reason) {
runOnUiThread(new Runnable() {
@Override
public void run() {
//其他用户脱离当时频道日本人妖回调
onRemoteUserLeft();
}
});
}
@Override
public void onUserMuteVideo(final int uid, final boolean muted) {
runOnUiThread(new Runnable() {
@Override
public void run() {
//其他用户已停发/已重发视频流回调
onRemoteUserVideoMuted(uid, muted);
}
});
}
};
private void onRemoteUserLeft() {
FrameLayout container = (FrameLayout) findViewById(R.id.remote_video_view_container);
container.removeAllViews();
//案牍可随意定制
View tipMsg = findViewById(R.id.quick_tips_when_use_agora_sdk);
tipMsg.setVisibility(View.VISIBLE);
}
private void onRemoteUserVideoMuted(int uid, boolean muted) {
FrameLayout container = (FrameLayout) findViewById(R.id.remote_video_view_container);
SurfaceView surfaceView = (SurfaceView) container.getChildAt(0);
Object tag = surfaceView.getTag();
if (tag != null && (Integer) tag == uid) {
surfaceView.setVisibility(muted ? View.GONE : View.VISIBLE);
}
}

翻开视频形式

e月亮图片nableVideo()办法用于翻开视频形式。可以在参加频道前或许通话中调用,在参加频道前调用,则主动敞开视频形式,在通话中调用则由音频形式切换为视频形式。调用 disableVideo() 办法可封闭视频形式。

setVideoProfile()办法设置视频编码特点(Profile)。每个特点对应一套视频参数,如分辨率、帧率、码率等。 当设备的摄像头不支撑指定的分辨率时,SDK 会主动挑选一个适宜的摄像头分辨率,可是编码分辨率依然用 setVideoProfile() 指定的。

该办法仅设置编码器编出的码流特点,或许跟终究显现的特点不一致,例如编码码流分辨率为 640x480,码流的旋转特点为 90 度,则显现出来的分辨率为竖屏形式。

/**
* Tutorial Step 2
* 翻开视频形式,并设置本地视频特点
*/
private void setupVideoProfile() {
//打555开视频形式
mRtcEngine.enableVideo();
//设置本地视频特点
mRtcEngine.setVideoProfile(Constants.VIDEO_PROFILE_360P, false);
}

设置本地视频显现特点

setupLocalVideo( VideoCanvas local )办法用于设置本地视频显现信息。运用程序经过调用此接口绑定本地视频流的显现视窗(view),并设置视频显现形式。 在运用程序开发中,通常在初始化后调用该办法进行本地视频设置,然后再参加频道。退出频道后,绑定依然有用,假如需求免除绑定,可以调用 setupLocalVideo(null) 。

/**
* Tutorial Step 3
* 设置本地视频显现特点
*/
private void setupLocalVideo() {
FrameLayout container = (FrameLayout) findViewById(R.id.local_video_view_container);
SurfaceView surfaceView = RtcEngine.CreateRendererView(getBaseContext());
surfaceView.setZOrderMediaOverlay(true);
container.addView(surfaceView);
mRtcEngine.setupLocalVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_ADAPTIVE, 0));
}

参加一个频道

joinChannel(String token,String channelName,String optionalInfo,int optionalUid )办法让用户参加通话频道,在同一个频道内的用户可以相互通话,多个用户参加同一个频道,可以群聊。 运用不同 App ID 的运用程序是不能互通的。假如已在通话中,用户有必要调用 leaveChannel() 退出当时通话,才干进入下一个频道。

/**
* Tutorial Step 4
* 参加一个频道
*/
private void joinChannel() {
//假如不指定UID,Agroa将主动生成并分配一个UID
mRtcEngine.joinChannel(null, "demoChannel1", "Extra Optional Data", 0);
}

设置远端视频显现特点

setupRemoteVideo( VideoCanvas remote)办法用于绑定长途用户和显现视图,即设定 uid 指定的用户用哪个视图显现。调用该接口时需求指定长途视频的 uid,一般可以在进频道前提早设置好。

假如运用程序不能事前知道对方的 uid,可以在 APP 收到 onUserJoined 事情时设置。假如启用了视频录制功用,视频录制效劳会做为一个哑客户端参加频道,因而其他客户端也会收到它的 onUserJoined 事情,APP 不该给它绑定视图(由于它不会发送视频流),假如 APP 不能辨认哑客户端,可以在 onFirstRemoteVideoDecoded 事情时再绑定视图。免除某个用户的绑定视图可以把 view 设置为空。退出频道后,SDK 会把长途用户的绑定联系清除去。

/**
* Tutorial Step 5
* 设置远端视频显现特点
*/
private void setupRemoteVideo(int uid) {
FrameLayout container = (FrameLayout) findViewById(R.id.remote_video_view_container);
if (container.getChildCount() >= 1) {
return;
}
SurfaceView surfaceView = RtcEngine.CreateRendererView(getBaseContext());
container.addView(surfaceView);
mRtcEngine.setupRemoteVideo(new VideoCanvas(surfaceView, VideoCanvas.RENDER_MODE_ADAPTIVE, uid));
surfaceView.setTag(uid);
//案牍可随意定制
View tipMsg = findViewById(R.id.quick_tips_when_use_agora_sdk);
tipMsg.setVisibility(View.GONE);
}

脱离当时频道

leaveChannel()办法用于脱离频道,即挂断或退出通话。

当调用 joinChannel() API 办法后,有必要调用 leaveChannel() 完毕通话,不然无法开端下一次通话。 不论当时是否在通话中,私密保养都可以调用 leaveChannel(),没有副作用。该办法会把会话相关的一切资源释放掉。该办法是异步操作,调用回来时并没有真实退出频道。在真实退出频道后,SDK 会触发 onLeaveChannel 回调。

/**
* Tutorial Step 6
* 脱离当时频道
*/
private void leaveChannel() {美丽的草原我的家,Android 开发实践:完结17人视频l谈天运用,我好想你
mRtcEngine.leaveChannel();
}
public void onEncCallClicked(View view) {
finish();
}
@Override
protected void onDestroy() {
super.onDestr美丽的草原我的家,Android 开发实践:完结17人视频l谈天运用,我好想你oy();
leaveChannel();
RtcEngine.destroy();
mRtcEngine = null;
}

办理摄像头

switchCamera()办法用于在前置/后置摄像头间切换。除此以外Agora还供给了一下办理摄像头的办法:例如setCameraTorchOn(boolean isOn)设置是否翻开闪光灯、setCameraAutoFocusFaceModeEnabled(boolean enabled)设置是否敞开人脸对焦功用等等。

/**
* Tutorial Step 7
* 切换前置/后置摄像头
*/
public void onSwitchCameraClicked(View view) {
mRtcEngine.switchCamera();
}

将自己静音

muteLocalAudioStream(boolean muted)办法用于静音/撤销静音。该办法可以答应/制止往网络发送本地音频流。但该办法并没水床有禁用麦克风,不影响录音状况。

/**
* Tutorial Step 8
* 将自己静音
*/
public void onLocalAudioMuteClicked(View view) {
ImageView iv = (ImageView) view;
if (iv.isSelected()) {
iv.setSelected(false);
iv.clearColorFilter();
} else {
iv.setSelected(true);
iv.setColorFilter(getResources().getColor(R.color.colorPrimary), PorterDuff.Mode.MULTIPLY);
}
mRtcEngine.muteLocalAudioStream(iv.isSelected());
}

暂停本地视频流

muteLocalVideoStream(boolean muted)办法用于暂停发送本地视频流,但该办法并没有禁用摄像头,不影响本地视频流获取。

/**
* Tutorial Step 9
* 暂停本地视频流
*/
public void onLocalVideoMuteClicked(View view) {
ImageView iv = (ImageView) view;
if (iv.isSelected()) {
iv.setSelected(false);
iv.clearColorFilter();
} else {
iv.setSelected(true);
iv.setColorFilter(getResources().getColor(R.color.colorPrimary), PorterDuff.Mode.MULTIPLY);
}
mRtcEngine.muteLocalVideoStream(iv.isSelected());
FrameLayout美观的符号 container = (FrameLayout) findViewById(R.id.local_video_view_container);
SurfaceView surfaceView = (SurfaceView) container.getChildAt(0);
surfaceView.setZOrderMediaOverlay(!iv.isSelected());
surfaceView.setVisibility(iv.isSelected() ? View.GONE : View.VISIBLE);
}

完结一对一视频通话

拿两部手机装置编译好的App,假如能看见两个自己,阐明你成功了。至此咱们现已完结了一对一的视频通话。接下来,咱们来进一步完结多人视频通话功用,首要需求处理两个问题:

  1. 跟着参加人数和他们的手机摄像头分辨率的改变,显现不同的UI,即所谓的“分屏”
  2. 点击分屏中的小窗,可以扩大显现该谈天窗

分屏

依据前期技能调研,分屏显现最好的办法是选用瀑布流结合动态谈天窗完结,这样比较便利的可以习惯UI的改变。所谓瀑布流,便是现在比较盛行的一种列表布局,会在蒲城天气预报界面上出现良莠不齐的多栏布局。咱们先完结一个瀑布流:

瀑布流的完结办法许多,本文选用结合 GridLayoutManager的RecyclerView 来完结。咱们首要自界说一个 RecyclerView,命名为 GridVideoViewContainer。中心代码如下:

int count = uids.size();
if (count <= 2) {
// 只要本地视频或谈天室内只要别的一个人
this.setLayoutManager(new LinearLayoutManager(activity.getApplicationContext(), orientation, false));
} else if (count > 2) {
// 多人谈天室
int itemSpanCount = getNearestSqrt(count);
this.setLayoutManager(new GridLayoutManager(activity.getApplicationContext(), itemSpanCount, orientation, false));
}

依据上面的代码可以看出,在谈天室里只要自己的本地视频或许只要别的一个人的时分,选用 LinearLayoutManager,这样的布局其实与前文的一对一谈天相似;而在真实含义的多人谈天室里,则选用 GridLayoutManager 完结瀑布流,其间 itemSpanCount 便是瀑布流的列数。

有了一个可用的瀑布流之后,下面咱们就可以完结动态谈天窗了:

动态谈天窗的要害在于 item 的巨细由视频的宽高比决议,因而 Adapter 及其对应的 layout 就该留意不要写死尺度。在 Adapter 里操控 item 详细尺度的代码如下:

if (force || mItemWidth == 0 || mItemHeight == 0) {
WindowManager windowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(outMetrics);
int count = uids.size();
int DividerX = 1;
int DividerY = 1;
if (count == 2) {
DividerY = 2;
} else if (count >= 3) {
DividerX = getNearestSqrt(count);
DividerY = (int) Math.ceil(count * 1.f / DividerX);
}
int width = outMetrics.widthPixels;
int height = outM美丽的草原我的家,Android 开发实践:完结17人视频l谈天运用,我好想你etrics.heightPixels;
if (width > height) {
mItemWidth = width / DividerY;
m微信最新版别ItemHeight = height / Divid大宝法王神通很厉的erX;
} else {
mItemWidth = width / DividerX;
mItemHeight = height / DividerY;
}
}

以上代码依据视频的数量确认了列数和行数,然后依据列数和屏幕宽度确认了视频的宽度,接着依据视频的宽高比和视频宽度确认了视频高度。一起也考虑了手机的反正屏状况(便是if (width > height)这行代码)。

该 Adapter 对应的 layout 的代码如下:

 xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/user_control_mask"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
android:id="@+id/default_avatar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
and国际歌roid:layout_centerInParent="true"
android:visibility="gone"
android:src="@drawable/icon_default_avatar"
android:contentDescription="DEFAULT_AVATAR" />
android:id="@+id/indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
android:layout_marginBottom="@dimen/video_indicator_bottom_margin"
android:contentDescription="VIDEO_INDICATOR" />
android:id="@+id/video_info_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginTop="24dp"
android:layout_marginStart="15dp"
android:layout_marginLeft="15dp"
android:visibility="gone"
android:orientation="vertical">
android:id="@+id/video_info_me白应鑫tadata"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
andr变形计20140616oid:singleLine="true"
style="@style/NotificationUIText" />


咱们可以看到,layout 中有关尺度的特点都 是wrap_content,这就使得 item 巨细随视频宽高比改变成为或许。

把分屏的布局写好之后,咱们就可以在每一个 item 上播映谈天视频了。

播映谈天视频

在 Agora SDK 中一个长途视频的显现只和该用户的 UID 有关,所以运用的数据源只需求简略界说为包含 UID 和对应的 SurfaceView 即可,就像这样:

 p美丽的草原我的家,Android 开发实践:完结17人视频l谈天运用,我好想你rivate final HashMap mUidsList = new HashMap<>();
```
每逢有人参加了咱们的谈天频道,都会触发`onFirstRemoteVideoDecoded(int uid, int width, int height, int elapsed)`办法,第一个 uid 便是他们的 UID;接下来咱们要为每个 item 新建一个 SurfaceView 并为其创立烘托视图,终究将它们参加方才创立好的mUidsList里并调用`setupRemoteVideo( VideoCanvas remote )`办法播映这个谈天视频。这个进程的完好代码如下:
```
@Override
public void onFirstRemoteVideoDecoded(int uid, int width, int height, int elapsed) {
doRenderRemoteUi(uid);
}
private void doRenderRemoteUi(final int uid) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (isFinishing()) {
return;
}
if (mUidsList.containsKey(uid)) {
return;
}
SurfaceView surfaceV = RtcEngine.CreateRendererView(getApplicationContext());
mUidsList.put(uid, surfaceV);
boolean useDefaultLayout = mLayoutType == LAYOUT_TYPE_DEFAULT;
surfaceV.setZOrderOnTop(true);
surfaceV.setZOrderMediaOverlay(true);
rtcEngine().setupRemoteVideo(new VideoCanvas(surfaceV, VideoCanvas.RENDER_MODE_HIDDEN, uid));
if (useDefaultLayout) {
log.debug("doRenderRemoteUi LAYOUT_TYPE_DEFAULT " + (美元兑换人民币汇率uid & 0xFFFFFFFFL));
switchToDefaultVideoView();
} else {
int bigBgUid = mSmallVideoViewAdapter == null ? uid : mSmallVideoViewAdapter.getExceptedUid();
log.debug("doRenderRemoteUi LAYOUT_TYPE_SMALL " + (uid & 0xFFFFFFFFL) + " " + (bigBgUid & 0xFFFFFFFFL));
switchToS三国之狼战全国mallVideoView(bigBgUid);
}
}
});
}

以上代码与前文中播映一对一视频的代码如出一撤,可是仔细的读者或许现已发现咱们并没有将生成的 SurfaceView 放在界面里,这正是与一对一视频的不同之处:咱们要在一个笼统的 VideoViewAdapter 类里将 SurfaceView 放出来,要害代码如下:

SurfaceView target = user.mView;
VideoViewAdapterUtil.stripView(target);
holderView.addView(target, 0, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));

一般 Android 工程师看见 holderView 就了解这是 ViewHolder 的 layout 的根 layout 了,而 user 是哪儿来的,详见文末的代码,文中不做赘述。

这样在多人谈天的时分咱们就能运用分屏的办法播映用户谈天视频了,假如想扩大某一个用户的视频该怎么办呢?

全屏和小窗

当用户双击某一个 item 的时分,他期望对应的视频可以全屏显现,而其他的视频则变成小窗口,那么咱们先界说一个双击事情接口:

public interface VideoViewEventListener {
void onItemDoubleClick(View v, Object item);
}
详细完结办法如下:
mGridVideoViewContainer.setItemEventHandler(new VideoViewEventListener() {
@Override
public void onItemDoubleClick(View v, Object item) {
log.debug("onItemDoubleClick " + v + " " + item + " " + mLayoutType);
if (mUidsList.size() < 2) {
return;
}
UserStatusData user = (UserStatusData) item;
int uid = (user.mUid == 0) ? config().mUid : user.mUid;
if (mLayo办公室热情utType == LAYOUT_TYPE_DEFAULT && mUidsList.size() != 1) {
switchToSmallVideoView(uid);
} else {
switchToDefaultVideoView();
}
}
});

将被选中的视频全屏播映的办法很简略了解,咱们只看生成小窗列表的办法:

private void switchToSmallVideoView(int bigBgUid) {
HashMap slice = new HashMap<>(1);
slice.put(bigBgUid, mUidsList.get(bigBgUid));
Iterator iterator = mUidsList.values().iterator();
while (iterator.hasNext()) {
SurfaceView s = iterator.next();
s.setZOrderOnTop(true);
s.setZOrderMediaOverlay(true);
}
mUidsList.get(bigBgUid).setZOrderOnTop(false);
mUidsList.get(bigBgUid).setZOrderMediaOverlay(false);
mGridVideoViewContainer.initViewContainer(this, bigBgUid, slice, mIsLandscape);
bindToSmallVideoView(bigBgUid);
mLayoutType = LAYOUT_TYPE_SMALL;
requestRemoteStreamType(mUidsList.size());
}

小窗列表要留意移除全屏的那个 UID,此外一切都和正常瀑布流视图相同,包含双击小窗的item将其全屏播映。

到了这儿咱们就现已运用 Agora SDK 完结了一个有根本功用的简略多人美丽的草原我的家,Android 开发实践:完结17人视频l谈天运用,我好想你谈天 demo,要产品化还有许多的东西要做,在这儿先做一个简略的总结吧!

总结

声网Agora SDK现已仅覆盖了干流的操作体系,集成功率也比较高,并且还支撑包含谈天,会议,直播等功用在内的多个形式的视频通话。SDK 中 API 规划根本可以满美丽的草原我的家,Android 开发实践:完结17人视频l谈天运用,我好想你足大部分的开发需求,并且躲藏了底层开发,只需求供给 SurfaceView 和 UID 即可播映视频,这样关于 App 层的开发者来说十分友爱。十分合适有视频谈天开发需求的开发者。