介绍
远程交流已成为大流行后交流中最重要的部分。它很有可能在未来也发挥重要作用。当今的移动应用程序通常包括语音或视频通话功能。但这非常复杂,需要大量时间来构建。这是Video SDK进入图片的地方。
视频SDK是一个平台,允许开发人员创建丰富的应用程序内体验,例如嵌入实时视频,语音,实时录制,实时流和实时消息。
Video SDK可用于JavaScript,ReactJS,React-Native,IOS,Android和Flutter无缝集成。 Video SDK还提供了一个预先构建的SDK,它有机会仅用10分钟就可以将实时通信整合到您的应用程序中!
!让我们使用视频SDK创建一对一的视频通话应用程序。
但是首先,我们需要创建视频SDK帐户并生成令牌。
先决条件
首先,您的开发环境应满足以下要求:
- Java Development Kit.
- Android Studio 3.0 or later.
- Android SDK API级别21或更高。
- 运行Android 5.0或更高版本的移动设备。
设置项目
步骤1:创建新项目
让我们从创建新项目开始。在Android Studio中,创建一个具有空活动的新项目。
然后,提供一个名称。我们将其命名为Onetoonedemo。
步骤2:集成视频SDK
- 将存储库添加到
settings.gradle
文件。
dependencyResolutionManagement{
repositories {
// ...
google()
mavenCentral()
maven { url 'https://jitpack.io' }
maven { url "https://maven.aliyun.com/repository/jcenter" }
}
}
- 在
build.gradle
文件中添加以下依赖项。
dependencies {
implementation 'live.videosdk:rtc-android-sdk:0.1.13'
// library to perform Network call to generate a meeting id
implementation 'com.amitshekhar.android:android-networking:1.0.2'
// other app dependencies
}
如果您的项目已设置了
android.useAndroidX = true
,则将android.enableJetifier = true
设置在gradle.properties
文件中以将您的项目迁移到Androidx并避免重复的类别冲突。
步骤3:将权限添加到您的项目中
在/app/Manifests/AndroidManifest.xml
中,添加</application>
之后的以下权限。
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
开始使用代码!
项目的结构
我们将创建两个屏幕。第一个屏幕将是Joining screen
,允许用户创建/加入会议,另一个是Meeting screen
,它将显示诸如WhatsApp View之类的参与者。
我们的项目结构看起来像这样。
app
├── java
│ ├── packagename
│ ├── JoinActivity
│ ├── MeetingActivity
├── res
│ ├── layout
│ │ ├── activity_join.xml
│ │ ├── activity_meeting.xml
您必须将
JoinActivity
设置为启动器活动。
创建加入屏幕
创建一个名为JoinActivity
创建UI以加入屏幕
加入屏幕将包括:
- 创建按钮 - 创建新的会议。
- textfield的会议ID-包含您要加入的会议ID。
- 加入按钮 - 与提供的会议加入会议。
在/app/res/layout/activity_join.xml
文件中,用以下内容替换内容。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
tools:context=".JoinActivity">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/material_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:contentInsetStart="0dp"
android:background="?attr/colorPrimary"
app:titleTextColor="@color/white" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<Button
android:id="@+id/btnCreateMeeting"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="Create Meeting" />
<TextView
style="@style/TextAppearance.AppCompat.Headline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="OR" />
<com.google.android.material.textfield.TextInputLayout style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginVertical="16dp"
android:hint="Enter Meeting ID">
<EditText
android:id="@+id/etMeetingId"
android:layout_width="250dp"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/btnJoinMeeting"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Join Meeting" />
</LinearLayout>
</LinearLayout>
集成创建会议API
- 您需要创建一个在JoinActivity中的字段采样,该字段可容纳Video SDK仪表板中生成的令牌。该令牌将用于视频SDK配置以及生成METICID。
public class JoinActivity extends AppCompatActivity {
//Replace with the token you generated from the VideoSDK Dashboard
private String sampleToken = "";
@Override
protected void onCreate(Bundle savedInstanceState) {
//...
}
}
- 在JOIN BUTTEN
onClick
事件上,它将使用令牌和METICID进行Naviagte至MeetingActivity
。
public class JoinActivity extends AppCompatActivity {
//Replace with the token you generated from the VideoSDK Dashboard
private String sampleToken ="";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_join);
final Button btnCreate = findViewById(R.id.btnCreateMeeting);
final Button btnJoin = findViewById(R.id.btnJoinMeeting);
final EditText etMeetingId = findViewById(R.id.etMeetingId);
//set title
Toolbar toolbar = findViewById(R.id.material_toolbar);
toolbar.setTitle("OneToOneDemo");
setSupportActionBar(toolbar);
btnCreate.setOnClickListener(v -> {
// we will explore this method in the next step
createMeeting(sampleToken);
});
btnJoin.setOnClickListener(v -> {
Intent intent = new Intent(JoinActivity.this, MeetingActivity.class);
intent.putExtra("token", sampleToken);
intent.putExtra("meetingId", etMeetingId.getText().toString());
startActivity(intent);
});
}
private void createMeeting(String token) {
}
}
- 对于创建按钮,在
createMeeting
方法下,我们将通过呼叫API并通过令牌和生成的MEDICID来生成会议ID。
public class JoinActivity extends AppCompatActivity {
//...onCreate
private void createMeeting(String token) {
// we will make an API call to VideoSDK Server to get a roomId
AndroidNetworking.post("https://api.videosdk.live/v2/rooms")
.addHeaders("Authorization", token) //we will pass the token in the Headers
.build()
.getAsJSONObject(new JSONObjectRequestListener() {
@Override
public void onResponse(JSONObject response) {
try {
// response will contain `roomId`
final String meetingId = response.getString("roomId");
// starting the MeetingActivity with received roomId and our sampleToken
Intent intent = new Intent(JoinActivity.this, MeetingActivity.class);
intent.putExtra("token", sampleToken);
intent.putExtra("meetingId", meetingId);
startActivity(intent);
} catch (JSONException e) {
e.printStackTrace();
}
}
@Override
public void onError(ANError anError) {
anError.printStackTrace();
Toast.makeText(JoinActivity.this, anError.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
}
- 我们的应用程序完全基于音频和视频通勤,这就是为什么我们需要要求运行时
RECORD_AUDIO
和CAMERA
。因此,我们将在JoinActivity
上实现权限逻辑。
public class JoinActivity extends AppCompatActivity {
private static final int PERMISSION_REQ_ID = 22;
private static final String[] REQUESTED_PERMISSIONS = {
Manifest.permission.RECORD_AUDIO,
Manifest.permission.CAMERA
};
private boolean checkSelfPermission(String permission, int requestCode) {
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, REQUESTED_PERMISSIONS, requestCode);
return false;
}
return true;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
//... button listeneres
checkSelfPermission(REQUESTED_PERMISSIONS[0], PERMISSION_REQ_ID);
checkSelfPermission(REQUESTED_PERMISSIONS[1], PERMISSION_REQ_ID);
}
}
您会遇到
Unresolved reference: MeetingActivity
错误,但不用担心。创建MeetingActivity
后,它将自动解决。
- 我们现在完成了加入屏幕,现在是时候在会议屏幕上创建参与者的视图了。
步骤4:创建会议屏幕
创建一个名为MeetingActivity
的新活动。
为会议屏幕创建UI
在/app/res/layout/activity_meeting.xml
文件中,用以下内容替换内容。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/mainLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
android:gravity="center"
android:orientation="vertical"
tools:context=".MeetingActivity">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/material_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/black"
app:contentInsetStart="0dp"
app:titleTextColor="@color/white">
<LinearLayout
android:id="@+id/meetingLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="14dp"
android:layout_marginTop="10dp"
android:orientation="horizontal">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/txtMeetingId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:fontFamily="sans-serif-medium"
android:textColor="@color/white"
android:textFontWeight="600"
android:textSize="16sp" />
<ImageButton
android:id="@+id/btnCopyContent"
android:layout_width="22dp"
android:layout_height="22sp"
android:layout_marginLeft="7dp"
android:layout_toRightOf="@+id/txtMeetingId"
android:backgroundTint="@color/black"
android:src="@drawable/ic_outline_content_copy_24" />
</RelativeLayout>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginEnd="10dp">
<ImageButton
android:id="@+id/btnSwitchCameraMode"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@color/black"
android:contentDescription="Switch Camera mode"
android:src="@drawable/ic_baseline_flip_camera_android_24" />
</LinearLayout>
</com.google.android.material.appbar.MaterialToolbar>
<FrameLayout
android:id="@+id/participants_frameLayout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="@color/black">
<androidx.cardview.widget.CardView
android:id="@+id/ParticipantCard"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="12dp"
android:layout_marginTop="3dp"
android:layout_marginRight="12dp"
android:layout_marginBottom="3dp"
android:backgroundTint="#2B3034"
android:visibility="gone"
app:cardCornerRadius="8dp"
app:strokeColor="#2B3034">
<ImageView
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_gravity="center"
android:src="@drawable/ic_baseline_person_24" />
<live.videosdk.rtc.android.VideoView
android:id="@+id/participantView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
</androidx.cardview.widget.CardView>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
<androidx.cardview.widget.CardView
android:id="@+id/LocalCard"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="12dp"
android:layout_marginTop="3dp"
android:layout_marginRight="12dp"
android:layout_marginBottom="3dp"
android:backgroundTint="#1A1C22"
app:cardCornerRadius="8dp"
app:strokeColor="#1A1C22">
<ImageView
android:id="@+id/localParticipant_img"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_gravity="center"
android:src="@drawable/ic_baseline_person_24" />
<live.videosdk.rtc.android.VideoView
android:id="@+id/localView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
</androidx.cardview.widget.CardView>
</FrameLayout>
<!-- add bottombar here-->
</LinearLayout>
<com.google.android.material.bottomappbar.BottomAppBar
android:id="@+id/bottomAppbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:backgroundTint="@color/black"
android:gravity="center_horizontal"
android:paddingVertical="5dp"
tools:ignore="BottomAppBar">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingEnd="16dp">
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/btnLeave"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="Leave Meeting"
android:src="@drawable/ic_end_call"
app:backgroundTint="#FF5D5D"
app:fabSize="normal"
app:tint="@color/white" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/btnMic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="90dp"
android:layout_toEndOf="@+id/btnLeave"
android:contentDescription="Toggle Mic"
android:src="@drawable/ic_mic_off"
app:backgroundTint="@color/white"
app:borderWidth="1dp"
app:fabSize="normal" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/btnWebcam"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="90dp"
android:layout_toEndOf="@+id/btnMic"
android:backgroundTint="@color/white"
android:contentDescription="Toggle Camera"
android:src="@drawable/ic_video_camera_off"
app:backgroundTint="@color/white"
app:borderWidth="1dp"
app:fabSize="normal" />
</RelativeLayout>
</com.google.android.material.bottomappbar.BottomAppBar>
复制项目中所需的图标和您项目的
res/drawable
文件夹中的粘贴。
初始化会议
从JoinActivity
获得令牌和会议后,我们需要...
- 初始化视频SDK
- 配置视频SDK 带有令牌。
- 用所需的参数(例如
meetingId
,participantName
,micEnabled
,micEnabled
和webcamEnabled,participantId
)初始化会议。 - 使用
meeting.join()
方法加入房间。
public class MeetingActivity extends AppCompatActivity {
private static Meeting meeting;
private boolean micEnabled = true;
private boolean webcamEnabled = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_meeting);
//
Toolbar toolbar = findViewById(R.id.material_toolbar);
toolbar.setTitle("");
setSupportActionBar(toolbar);
//
String token = getIntent().getStringExtra("token");
final String meetingId = getIntent().getStringExtra("meetingId");
// set participant name
String localParticipantName = "Alex";
// Initialize VideoSDK
VideoSDK.initialize(getApplicationContext());
// pass the token generated from api server
VideoSDK.config(token);
// create a new meeting instance
meeting = VideoSDK.initMeeting(
MeetingActivity.this, meetingId, localParticipantName,
micEnabled, webcamEnabled, null, null
);
// join the meeting
if (meeting != null) meeting.join();
//
TextView textMeetingId = findViewById(R.id.txtMeetingId);
textMeetingId.setText(meetingId);
// copy meetingId to clipboard
((ImageButton) findViewById(R.id.btnCopyContent)).setOnClickListener(v -> copyTextToClipboard(meetingId));
}
private void copyTextToClipboard(String text) {
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("Copied text", text);
clipboard.setPrimaryClip(clip);
Toast.makeText(MeetingActivity.this, "Copied to clipboard!", Toast.LENGTH_SHORT).show();
}
}
步骤5:处理当地参与者媒体
我们需要对以下Views
进行单击:
- 麦克风按钮
- 网络摄像头按钮
- 开关相机按钮
- 离开按钮
添加以下实现:
public class MeetingActivity extends AppCompatActivity {
private FloatingActionButton btnWebcam, btnMic, btnLeave;
private ImageButton btnSwitchCameraMode;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_meeting);
//
btnMic = findViewById(R.id.btnMic);
btnWebcam = findViewById(R.id.btnWebcam);
btnLeave = findViewById(R.id.btnLeave);
btnSwitchCameraMode = findViewById(R.id.btnSwitchCameraMode);
//...
// actions
setActionListeners();
}
private void setActionListeners() {
// Toggle mic
btnMic.setOnClickListener(view -> toggleMic());
// Toggle webcam
btnWebcam.setOnClickListener(view -> toggleWebCam());
// Leave meeting
btnLeave.setOnClickListener(view -> {
// this will make the local participant leave the meeting
meeting.leave();
});
// Switch camera
btnSwitchCameraMode.setOnClickListener(view -> {
//a participant can change stream from front/rear camera during the meeting.
meeting.changeWebcam();
});
}
}
private void toggleMic() {
if (micEnabled) {
// this will mute the local participant's mic
meeting.muteMic();
} else {
// this will unmute the local participant's mic
meeting.unmuteMic();
}
micEnabled = !micEnabled;
// change mic icon according to micEnable status
toggleMicIcon();
}
@SuppressLint("ResourceType")
private void toggleMicIcon() {
if (micEnabled) {
btnMic.setImageResource(R.drawable.ic_mic_on);
btnMic.setColorFilter(Color.WHITE);
Drawable buttonDrawable = btnMic.getBackground();
buttonDrawable = DrawableCompat.wrap(buttonDrawable);
//the color is a direct color int and not a color resource
if (buttonDrawable != null) DrawableCompat.setTint(buttonDrawable, Color.TRANSPARENT);
btnMic.setBackground(buttonDrawable);
} else {
btnMic.setImageResource(R.drawable.ic_mic_off);
btnMic.setColorFilter(Color.BLACK);
Drawable buttonDrawable = btnMic.getBackground();
buttonDrawable = DrawableCompat.wrap(buttonDrawable);
//the color is a direct color int and not a color resource
if (buttonDrawable != null) DrawableCompat.setTint(buttonDrawable, Color.WHITE);
btnMic.setBackground(buttonDrawable);
}
}
private void toggleWebCam() {
if (webcamEnabled) {
// this will disable the local participant webcam
meeting.disableWebcam();
} else {
// this will enable the local participant webcam
meeting.enableWebcam();
}
webcamEnabled = !webcamEnabled;
// change webCam icon according to webcamEnabled status
toggleWebcamIcon();
}
@SuppressLint("ResourceType")
private void toggleWebcamIcon() {
if (webcamEnabled) {
btnWebcam.setImageResource(R.drawable.ic_video_camera);
btnWebcam.setColorFilter(Color.WHITE);
Drawable buttonDrawable = btnWebcam.getBackground();
buttonDrawable = DrawableCompat.wrap(buttonDrawable);
//the color is a direct color int and not a color resource
if (buttonDrawable != null) DrawableCompat.setTint(buttonDrawable, Color.TRANSPARENT);
btnWebcam.setBackground(buttonDrawable);
} else {
btnWebcam.setImageResource(R.drawable.ic_video_camera_off);
btnWebcam.setColorFilter(Color.BLACK);
Drawable buttonDrawable = btnWebcam.getBackground();
buttonDrawable = DrawableCompat.wrap(buttonDrawable);
//the color is a direct color int and not a color resource
if (buttonDrawable != null) DrawableCompat.setTint(buttonDrawable, Color.WHITE);
btnWebcam.setBackground(buttonDrawable);
}
}
设置本地参与者视图
要设置参与者视图,我们必须实现ParticipantEventListener
抽象类的所有方法,并使用Participant
类的addEventListener()
方法将侦听器添加到Participant
类中。 ParticipantEventListener
类有两种方法:
-
onStreamEnabled
-每当参与者启用麦克风/网络摄像头时,此事件将被触发并返回Stream
。 -
onStreamDisabled
-每当参与者在会议中禁用麦克风/网络摄像头时,此事件将被触发并返回Stream
。
public class MeetingActivity extends AppCompatActivity {
private VideoView localView;
private VideoView participantView;
private CardView localCard, participantCard;
private ImageView localParticipantImg;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_meeting);
//...
localCard = findViewById(R.id.LocalCard);
participantCard = findViewById(R.id.ParticipantCard);
localView = findViewById(R.id.localView);
participantView = findViewById(R.id.localParticipant);
localParticipantImg = findViewById(R.id.localParticipant_img);
//...
// setup local participant view
setLocalListeners();
}
private void setLocalListeners() {
meeting.getLocalParticipant().addEventListener(new ParticipantEventListener() {
@Override
public void onStreamEnabled(Stream stream) {
if (stream.getKind().equalsIgnoreCase("video")) {
VideoTrack track = (VideoTrack) stream.getTrack();
localView.setVisibility(View.VISIBLE);
localView.addTrack(track);
localView.setZOrderMediaOverlay(true);
localCard.bringToFront();
}
}
@Override
public void onStreamDisabled(Stream stream) {
if (stream.getKind().equalsIgnoreCase("video")) {
localView.removeTrack();
localView.setVisibility(View.GONE);
}
}
});
}
}
设置远程参与者视图
private final ParticipantEventListener participantEventListener = new ParticipantEventListener() {
// trigger when participant enabled mic/webcam
@Override
public void onStreamEnabled(Stream stream) {
if (stream.getKind().equalsIgnoreCase("video")) {
localView.setZOrderMediaOverlay(true);
localCard.bringToFront();
VideoTrack track = (VideoTrack) stream.getTrack();
participantView.setVisibility(View.VISIBLE);
participantView.addTrack(track);
}
}
// trigger when participant disabled mic/webcam
@Override
public void onStreamDisabled(Stream stream) {
if (stream.getKind().equalsIgnoreCase("video")) {
participantView.removeTrack();
participantView.setVisibility(View.GONE);
}
}
};
处理会议活动并管理参与者的观点
- 添加
MeetingEventListener
进行听力活动,例如会议/左和参与者加入/左。
public class MeetingActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_meeting);
//...
// handle meeting events
meeting.addEventListener(meetingEventListener);
}
private final MeetingEventListener meetingEventListener = new MeetingEventListener() {
@Override
public void onMeetingJoined() {
// change mic,webCam icon after meeting successfully joined
toggleMicIcon();
toggleWebcamIcon();
}
@Override
public void onMeetingLeft() {
if (!isDestroyed()) {
Intent intent = new Intent(MeetingActivity.this, JoinActivity.class);
startActivity(intent);
finish();
}
}
@Override
public void onParticipantJoined(Participant participant) {
// Display local participant as miniView when other participant joined
changeLocalParticipantView(true);
Toast.makeText(MeetingActivity.this, participant.getDisplayName() + " joined",
Toast.LENGTH_SHORT).show();
participant.addEventListener(participantEventListener);
}
@Override
public void onParticipantLeft(Participant participant) {
// Display local participant as largeView when other participant left
changeLocalParticipantView(false);
Toast.makeText(MeetingActivity.this, participant.getDisplayName() + " left",
Toast.LENGTH_SHORT).show();
}
};
}
-
changeLocalParticipantView(isMiniView: Boolean)
函数首先检查本地参与者的视频是否显示为小型视图或大视法。 - 如果会议只有一名参与者(当地参与者),则将本地参与者显示为大浏览。
- 当另一名参与者(当地参与者除外)加入时,
changeLocalParticipantView(true)
被称为。结果,本地参与者被显示为量表,而其他参与者则显示为大浏览。
private void changeLocalParticipantView(boolean isMiniView) {
if(isMiniView)
{
// show localCard as miniView
localCard.setLayoutParams(new CardView.LayoutParams(300, 430, Gravity.RIGHT | Gravity.BOTTOM));
ViewGroup.MarginLayoutParams cardViewMarginParams = (ViewGroup.MarginLayoutParams) localCard.getLayoutParams();
cardViewMarginParams.setMargins(30, 0, 60, 40);
localCard.requestLayout();
// set height-width of localParticipant_img
localParticipantImg.setLayoutParams(new FrameLayout.LayoutParams(150, 150, Gravity.CENTER));
participantCard.setVisibility(View.VISIBLE);
}else{
// show localCard as largeView
localCard.setLayoutParams(new CardView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
ViewGroup.MarginLayoutParams cardViewMarginParams = (ViewGroup.MarginLayoutParams) localCard.getLayoutParams();
cardViewMarginParams.setMargins(30, 5, 30, 30);
localCard.requestLayout();
// set height-width of localParticipant_img
localParticipantImg.setLayoutParams(new FrameLayout.LayoutParams(400, 400, Gravity.CENTER));
participantCard.setVisibility(View.GONE);
}
}
破坏一切
当应用程序关闭并且不再使用时,我们需要发布资源。用以下代码覆盖onDestroy
:
protected void onDestroy() {
if(meeting !=null)
{
meeting.removeAllListeners();
meeting.getLocalParticipant().removeAllListeners();
meeting.leave();
meeting = null;
}
if (participantView != null) {
participantView.setVisibility(View.GONE);
participantView.releaseSurfaceViewRenderer();
}
if (localView != null) {
localView.setVisibility(View.GONE);
localView.releaseSurfaceViewRenderer();
}
super.onDestroy();
}
java.lang.IllegalStateException: This Activity already has an action bar supplied by the window decor. Do not request Window.FEATURE_SUPPORT_ACTION_BAR and set windowActionBar to false in your theme to use a Toolbar instead.
如果您在运行时遇到此错误,请在theme.xml
文件中包含这些行。
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
应用演示
tadaa!我们的应用已经准备好了。容易,不是吗?
在两个不同的设备上安装并运行该应用程序,并确保它们连接到Internet。
此应用仅支持2位参与者,它管理不超过2个参与者。如果您想处理2个以上的参与者,请结帐我们的组呼叫示例here。
结论
- 在此博客中,我们了解了什么是视频SDK,如何从视频SDK dashboard获得访问令牌,以及如何使用视频SDK创建一个一对一的视频呼叫应用程序。
- 继续创建高级功能,例如屏幕共享,聊天等。
- 要查看应用程序的完整实现,请查看此GitHub repository。
- 如果您遇到任何问题或有疑问,请加入我们的Discord community。
更多的Android资源
- Android One-To-One video calling app with Kotlin
- Android Interactive Live Streaming App with Kotlin
- Android Video Conferencing App with Kotlin example code
- Android Interactive Live Streaming App with Kotlin example code
- Android Interactive Live Streaming App with Java example code
- Android Video Conferencing App with Java example code