废话
今天我们来编写视频语音通话界面
在即时通信app中,除了基本的文本、语音、图片聊天外,还要有实时语音和视频聊天功能,这个功能是每个即时通信app需要有的,下面我们就来看看如何编写
创建Activity
public class MediaActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_media);
fbv();
init();
event();
}
}
这个是音视频通话的Activity
我们可以看到,在onCreate中加载了布局R.layout.activity_media,我们看看这个布局是怎么写的
activity_media.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.yk.mchat.app.widget.VideoLayout
android:id="@+id/media_video_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.yk.mchat.app.widget.VoiceLayout
android:id="@+id/media_voice_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
可以看到,这是一个相对布局,里面有两个子View
- VideoLayout
- VoiceLayout
这两个子View分别是视频和音频通话的布局,并且这两个View不是原生的,需要我们自己编写,后面我们会详细讲解这两个布局,我们先进行下一步
接下来是setContentView后面的三个方法
- fbv
- init
- event
fbv
private void fbv() {
mVideoLayout = findViewById(R.id.media_video_layout);
mVoiceLayout = findViewById(R.id.media_voice_layout);
}
init
private void init() {
initUser();
initMedia();
}
initUser
private void initUser() {
if (null != getIntent().getSerializableExtra("to_user")) {
mToUser = (User) getIntent().getSerializableExtra("to_user");
mVoiceLayout.setUserInfo(mToUser);
} else {
mToUsername = getIntent().getStringExtra("from");
loadToUser();
}
}
loadToUser
private void loadToUser() {
BmobQuery<User> query = new BmobQuery<>();
query.addWhereEqualTo("username", mToUsername);
query.include("friends");
query.findObjects(new FindListener<User>() {
@Override
public void done(List<User> list, BmobException e) {
if (e == null) {
if (list.size() != 0) {
mToUser = list.get(0);
mVoiceLayout.setUserInfo(mToUser);
}
}
}
});
}
initMedia
private void initMedia() {
EMClient.getInstance().callManager().addCallStateChangeListener(mEmCallStateChangeListener);
mType = getIntent().getStringExtra("call_type");
if (mType.equals("call")) {
call();
} else if (mType.equals("answer")) {
answer();
}
}
call
private void call() {
mVoiceLayout.setType(VoiceLayout.TYPE_CALL);
mMediaType = getIntent().getStringExtra("media_type");
if (mMediaType.equals("voice")) {
callVoice();
mVideoLayout.setVisibility(View.GONE);
} else if (mMediaType.equals("video")) {
callVideo();
setSurfaceView();
}
}
callVoice
private void callVoice() {
try {
EMClient.getInstance().callManager().makeVoiceCall(mToUsername);
} catch (EMServiceNotReadyException e) {
e.printStackTrace();
}
}
callVideo
private void callVideo() {
try {
EMClient.getInstance().callManager().makeVideoCall(mToUsername);
} catch (EMServiceNotReadyException e) {
e.printStackTrace();
}
}
answer
private void answer() {
mVoiceLayout.setType(VoiceLayout.TYPE_ANSWER);
mMediaType = getIntent().getStringExtra("media_type");
if (mMediaType.equals("voice")) {
mVideoLayout.setVisibility(View.GONE);
} else if (mMediaType.equals("video")) {
setSurfaceView();
}
}
setSurfaceView
private void setSurfaceView() {
mLocalSurfaceView = new EMLocalSurfaceView(MediaActivity.this);
mRemoteSurfaceView = new EMOppositeSurfaceView(MediaActivity.this);
EMClient.getInstance().callManager().setSurfaceView(mLocalSurfaceView, mRemoteSurfaceView);
mVideoLayout.addView(mLocalSurfaceView);
}
上面的方法基本上可以从名字上看出功能,最后还有一个就是通话状态监听
EMCallStateChangeListener mEmCallStateChangeListener = new EMCallStateChangeListener() {
@Override
public void onCallStateChanged(CallState callState, CallError error) {
switch (callState) {
case CONNECTING: // 正在连接对方
break;
case CONNECTED: // 双方已经建立连接
break;
case ACCEPTED: // 电话接通成功
mVideoLayout.addView(mRemoteSurfaceView, 0);
mVoiceLayout.connect();
break;
case DISCONNECTED: // 电话断了
finish();
break;
case NETWORK_UNSTABLE: //网络不稳定
if (error == CallError.ERROR_NO_DATA) {
//无通话数据
} else {
}
break;
case NETWORK_NORMAL: //网络恢复正常
break;
default:
break;
}
}
};
基本代码就这些,下面是音视频通话界面的完整代码
package com.yk.mchat.app.activity;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import com.hyphenate.chat.EMCallStateChangeListener;
import com.hyphenate.chat.EMClient;
import com.hyphenate.exceptions.EMNoActiveCallException;
import com.hyphenate.exceptions.EMServiceNotReadyException;
import com.hyphenate.media.EMLocalSurfaceView;
import com.hyphenate.media.EMOppositeSurfaceView;
import com.yk.mchat.R;
import com.yk.mchat.app.widget.VideoLayout;
import com.yk.mchat.app.widget.VoiceLayout;
import com.yk.mchat.model.contacts.User;
import java.util.List;
import cn.bmob.v3.BmobQuery;
import cn.bmob.v3.exception.BmobException;
import cn.bmob.v3.listener.FindListener;
public class MediaActivity extends AppCompatActivity {
private String mType;
private String mMediaType;
private User mToUser;
private String mToUsername;
private VideoLayout mVideoLayout;
private VoiceLayout mVoiceLayout;
private EMLocalSurfaceView mLocalSurfaceView;
private EMOppositeSurfaceView mRemoteSurfaceView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_media);
fbv();
init();
event();
}
private void fbv() {
mVideoLayout = findViewById(R.id.media_video_layout);
mVoiceLayout = findViewById(R.id.media_voice_layout);
}
private void init() {
initUser();
initMedia();
}
private void initUser() {
if (null != getIntent().getSerializableExtra("to_user")) {
mToUser = (User) getIntent().getSerializableExtra("to_user");
mVoiceLayout.setUserInfo(mToUser);
} else {
mToUsername = getIntent().getStringExtra("from");
loadToUser();
}
}
private void loadToUser() {
BmobQuery<User> query = new BmobQuery<>();
query.addWhereEqualTo("username", mToUsername);
query.include("friends");
query.findObjects(new FindListener<User>() {
@Override
public void done(List<User> list, BmobException e) {
if (e == null) {
if (list.size() != 0) {
mToUser = list.get(0);
mVoiceLayout.setUserInfo(mToUser);
}
}
}
});
}
private void initMedia() {
EMClient.getInstance().callManager().addCallStateChangeListener(mEmCallStateChangeListener);
mType = getIntent().getStringExtra("call_type");
if (mType.equals("call")) {
call();
} else if (mType.equals("answer")) {
answer();
}
}
private void setSurfaceView() {
mLocalSurfaceView = new EMLocalSurfaceView(MediaActivity.this);
mRemoteSurfaceView = new EMOppositeSurfaceView(MediaActivity.this);
EMClient.getInstance().callManager().setSurfaceView(mLocalSurfaceView, mRemoteSurfaceView);
mVideoLayout.addView(mLocalSurfaceView);
}
private void call() {
mVoiceLayout.setType(VoiceLayout.TYPE_CALL);
mMediaType = getIntent().getStringExtra("media_type");
if (mMediaType.equals("voice")) {
callVoice();
mVideoLayout.setVisibility(View.GONE);
} else if (mMediaType.equals("video")) {
callVideo();
setSurfaceView();
}
}
private void callVoice() {
try {
EMClient.getInstance().callManager().makeVoiceCall(mToUsername);
} catch (EMServiceNotReadyException e) {
e.printStackTrace();
}
}
private void callVideo() {
try {
EMClient.getInstance().callManager().makeVideoCall(mToUsername);
} catch (EMServiceNotReadyException e) {
e.printStackTrace();
}
}
private void answer() {
mVoiceLayout.setType(VoiceLayout.TYPE_ANSWER);
mMediaType = getIntent().getStringExtra("media_type");
if (mMediaType.equals("voice")) {
mVideoLayout.setVisibility(View.GONE);
} else if (mMediaType.equals("video")) {
setSurfaceView();
}
}
private void event() {
}
EMCallStateChangeListener mEmCallStateChangeListener = new EMCallStateChangeListener() {
@Override
public void onCallStateChanged(CallState callState, CallError error) {
switch (callState) {
case CONNECTING: // 正在连接对方
break;
case CONNECTED: // 双方已经建立连接
break;
case ACCEPTED: // 电话接通成功
mVideoLayout.addView(mRemoteSurfaceView, 0);
mVoiceLayout.connect();
break;
case DISCONNECTED: // 电话断了
finish();
break;
case NETWORK_UNSTABLE: //网络不稳定
if (error == CallError.ERROR_NO_DATA) {
//无通话数据
} else {
}
break;
case NETWORK_NORMAL: //网络恢复正常
break;
default:
break;
}
}
};
}
今天就到这里