实时音视频通话涉及到的技术栈、人力成本、硬件成本非常大,一般个人开发者基本无法独立完成一个功能健全并且稳定的实时音视频应用。本文介绍一天之内,无任何实时音视频低层技术的android开发者完成实时相亲房APP,效果如下:

笔者从搜索引擎上搜了一些第三方库,综合对比了一下,最终选择了即构)。因为一方面他们提供了非常全的音视频通话能力,视频通话SDK使用起来也非常简单;另一方面他们每个月提供了10000分钟的免费额度,对于个人开发者来说足够用了。如果超过了免费额度,说明应用有一定的流量了,到那时候花点钱扩一下容量就好。

详细开发文档请参考https://doc-zh.zego.im/article/7627)

1 需要用到的多人实时音视频通话能力

实现Android端多人实时视频通话,可以简单地抽象成如下几个模块:

  1. 获取本地视频流,并推送到服务器。
  2. 拉取各个用户视频流,并在终端展示。
  3. 房间管理,管理当前多人房间的用户连接状态、观众登录登出等。

接下来我们介绍基于即构音视频通话SDK来实现上述模块功能。

1.1 音视频SDK准备工作

1.1.1 集成音视频SDK

音视频通话SDK集成方式请直接参考官方文档https://doc-zh.zego.im/article/195), 这里不过多描述。

1.1.2 音视频通话sdk初始化引擎

有了即构的实时音视频库后,接下来需要初始化库,得到一个ZegoExpressEngine引擎对象。这个对象比较重要,因为接下来我们的一切对音视频流的控制都是通过此对象实现。

ZegoEngineProfile profile = new ZegoEngineProfile();
profile.appID = KeyCenter.APPID;
profile.scenario = ZegoScenario.GENERAL; // 通用场景接入
profile.application = app;
ZegoExpressEngine engine = = ZegoExpressEngine.createEngine(profile, null);

需要注意的是,这里第二行有APPID参数,这两个参数需要前往https://console.zego.im)创建一个项目,即可获取当前项目对应的APPID

另外,ZegoExpressEngine.createEngine函数还有一个handler参数,这个参数对象用于监听当前房间的一些信息,如相亲房用户登录登出,用户发送实时消息等。这里我们先挖个坑,在后面详细描述这个对象。

1.2 相亲房的房间登录登出

房间是用来承载多人音视频通话的空间,一切实时音视频都是发生在房间。因此,首先要登录房间:

ZegoUser user = new ZegoUser(userID, userName);
ZegoRoomConfig config = new ZegoRoomConfig();
config.token = token; // 请求开发者服务端获取
config.isUserStatusNotify = true;
engine.loginRoom(roomId, user, config);

注意,需要保证userID唯一。roomID也要唯一,如果当前roomID已存在,那么加入此房间,如果不存在,则创建房间。

退出房间比较简单:执行engine.logoutRoom();即可退出。

注意到此函数需要传入token参数。token参数是采用对称算法生成。其大致原理如下:

  1. 生成一个随机数,并将有效时长等其他相关参数,按照固定格式排列得到未加密版的token
  2. 使用密钥(在即构官方控制台中获取,每个APPID对应一个密钥)并使用对称加密算法加密,得到加密版的token,这个token是给客户端登录时使用的。

具体的代码实现操作请参考文末提供的源码,这里不再过多描述。

1.3 相亲房实时视频推流

如果希望别人能拉取到自己的实时视频画面,需要先将自己的视频流推送出去。

engine.startPublishingStream(streamID);

注意,这里的streamID用于标识用户的视频流,因此需要保证唯一,因为其他用户在拉取视频流时,是根据这个标识来区分的。

1.4 相亲房实时视频画面显示

1.4.1 预览本地视频

ZegoCanvas canvas = new ZegoCanvas(textureView);
//设置显示图像填充比例方式
canvas.viewMode = ASPECT_FILL;
engine.startPreview(canvas);

textureView是个TextureView对象,可以在布局文件中提前布局。

1.4.2 预览远程视频

ZegoCanvas canvas = new ZegoCanvas(textureView);
//设置显示图像填充比例方式
canvas.viewMode = ASPECT_FILL;
engine.startPlayingStream(streamID, canvas);

预览远程用户与本地画面预览类似,需要差别是需要提供远程用户推流的streamID

2 无后台开发

用户唯一性、视频流唯一性、房间号的唯一性等需要我们自己准备一台服务器来管理,如果读者有个人服务器,实现起来也非常简单。

考虑到大部分读者没有个人服务器,同时也为了方便本文提供的代码可以直接在任何网络环境下运行,接下来我们实现无后台的方案:

我们假设每个用户都是社会主义三好青年,不会去破解APP冒充房主,创建房间的房主就是管理员,管理员向房间内各个用户发送实时消息,房间内各个成员去执行管理员的指令,实现房间管理的能力。

这就需要用到即构实时音视频SDK的房间内实时发送消息能力。

2.1 房间发送实时消息

广播消息:

public void sendBroadcastMessage(String roomID,
String msg,
IZegoIMSendBroadcastMessageCallback callback);

roomIDmessage就不需要再解释,callback对象是回调用户,用于获取消息发送是否成功。

一对多发送消息:

public void sendCustomCommand(String roomID,
String msg,
ArrayList<ZegoUser> toUserList,
IZegoIMSendCustomCommandCallback callback);

ZegoUser类型在前面登录房间时我们已经介绍过,其他参数含义同上。

2.2 相亲房内接收实时消息

前面在介绍创建ZegoExpressEngine引擎时,需要提供一个handler参数,这里派上用场了,它是抽象类IZegoEventHandler的子类对象,用于执行回调事件,例如接收广播消息:

@Override
public void onIMRecvBroadcastMessage(String roomID,
ArrayList<ZegoBroadcastMessageInfo> messageList) {
// 收到广播消息
Log.d(TAG, "收到广播消息");
}

接收到一对多消息:

@Override
public void onIMRecvCustomCommand(String roomID,
ZegoUser fromUser,
String command) {
Log.d(TAG, "收到一对多消息");
}

2.3 IZegoEventHandler其他需要用到的回调函数

房间内用户登录、登出回调,在用户登录时,可以将房间信息如房间名称,房主ID等发送给登录的用户:

@Override
public void onRoomUserUpdate(String roomID,
ZegoUpdateType updateType,
ArrayList<ZegoUser> userList) {
super.onRoomUserUpdate(roomID, updateType, userList);
if (updateType == ZegoUpdateType.ADD) {
Log.d(TAG, "用户登录");
} else if (updateType == ZegoUpdateType.DELETE) {
Log.d(TAG, "用户登出");
} }

获取音量大小,用于显示每个连麦的用户的说话音量:

@Override
// soundLevel取值为0~100
public void onCapturedSoundLevelUpdate(float soundLevel) {
Log.d(TAG, "收到自己音浪消息...");
}
@Override
public void onRemoteSoundLevelUpdate(HashMap<String, Float> soundLevels) {
Log.d(TAG, "收到远程音浪消息...");
}

与房间连接状态回调,用于判断当前登录状态。

@Override
public void onRoomStateUpdate(String roomID,
ZegoRoomState state,
int errorCode,
JSONObject extendedData) {
super.onRoomStateUpdate(roomID, state, errorCode, extendedData);
if (state == ZegoRoomState.CONNECTED) {
Log.d(TAG, "房间连接成功...");
} else if (state == ZegoRoomState.CONNECTING) {
Log.d(TAG, "房间连接中...");
} else if (state == ZegoRoomState.DISCONNECTED) {
Log.d(TAG, "房间连接断开...");
}
}

3 正式开发相亲房APP

有了前面的音视频能力的基础铺垫后,我们接下来进入正式的相亲房APP开发.

3.1 创建房间/进入房间界面功能与实现

对于创建房间按钮,需要判断房间是否已存在, 可以通过获取指定的房间ID里面人数是否为0来判断房间是否已存在。同理,对于进入房间的用户来说,需要判断房间内用户数量是否大于0来判断房间是否存在。

例如,查询房间号为123456房间的用户数量:

https://rtc-api.zego.im/?Action=DescribeUserNum
&RoomId[]=123
&RoomId[]=456
&<公共请求参数>

注意,调用频率限制(同一个 AppID 下所有房间):10 次/秒(测试环境:1 次/秒)

具体使用方法参考这里https://doc-zh.zego.im/article/8780)

3.2 相亲场景的月老

我们把创建房间的房主称为月老。月老创建房间后:

  1. 监听用户进入房间,当有用户进入房间时,向其发送当前房间的房间名称、月老的UserID、当前正在连麦的用户信息及其视频流StreamID
  2. 监听用户消息,接收房间内用户发送的消息,消息分为几类:请求上麦、下麦、用户已静音等连麦相关消息。
  3. 当有连麦用户有变动,将连麦用户信息广播给各个用户。

3.3 相亲场景的用户

普通用户进入房间后:

  1. 第一时间得到月老发送的房间信息,包括房间名称,月老UserID、正在连麦用户信息及其视频流StreamID
  2. 得到连麦用户信息后,自动拉取连麦用户的StreamID对应的视频流, 并在界面展示。
  3. 请求连麦,向月老发送请求连麦信息。
  4. 每次收到月老发送的同步房间信息时,自动将拉取正在连麦的用户视频流,并取消下麦视频流的展示。

3.4 实时视频播放预览画面

在整个相亲房APP中,核心是拉取远程视频流和播放本地预览。前面提到,播放预览画面分为本地预览和拉取视频流预览。为了便于调用,将两种方式封装为一个函数playStream:

private void playStream(ZegoExpressEngine engine, String streamId, TextureView tv) {
if (streamId == null) return;
if (streamId.equals(controller.mUserInfo.uid)) {
Log.e(TAG, "预览自己");
engine.startPublishingStream(streamId);//上传视频流
Zego.playPreview(engine, tv, null);
} else {
Log.e(TAG, "拉取视频流");
engine.stopPlayingStream(streamId);
Zego.playPreview(engine, tv, streamId);
}
}

playStream函数指定要拉取的streamID和用于显示的TextureView。在函数里面判断当前streamID是否属于自己,如果属于自己则直接预览本地即可,否则拉取远程视频流。其中Zero.playPreview如下:

public static void playPreview(ZegoExpressEngine engine, TextureView tv, String streamId) {
ZegoCanvas canvas = new ZegoCanvas(tv);
canvas.viewMode = ASPECT_FILL;
if (streamId == null) {//本地预览
engine.startPreview(canvas);
} else {//拉取视频流
engine.startPlayingStream(streamId, canvas);
}
}

根据传入的streamID是否为null来判断是拉取远程视频还是播放本地预览。

4 相亲房demo的代码分享

无后台版相亲房APP源码下载:(https://github.com/KaleTom/xiangqingfang

从零实现在线云相亲APP|程序员脱单神器(内附源码Demo)的更多相关文章

  1. .net程序员面试小结(内附一些面试题和答案)

    今天下午去面试,面试官和HR小姐姐都很好,没有做面试题,用聊天的方式来交流技术,整个过程很轻松,从中也学到了很多知识. 下面就来总结一下面试过程. 一.深刻了解自己的简历 无论是HR还是技术面试人,首 ...

  2. 微信小程序之蓝牙开发(详细读数据、写数据、附源码)

    本文将详细介绍微信小程序的蓝牙开发流程(附源码)准备:微信只支持低功耗蓝牙也就是蓝牙4.0,普通的蓝牙模块是用不了的,一定要注意. 蓝牙可以连TTL接到电脑上,再用XCOM调试 一开始定义的变量 va ...

  3. 关于APP程序员泡沫经济

    这些年,移动互联网非常火,火到掀起学习iOS.安卓以及H5的热潮.有人将这些新技术作为自己的实力补充,增加竞争力:更多的人将它们作为主业,专职做移动开发.但是,即便有移动开发人员不断涌入,对整个行业来 ...

  4. 微信小程序——智能小秘“遥知之”源码分享(语义理解基于olami)

    微信小程序智能生活小秘书开发详解 >>>>>>>>>>>>>>>>>>>>> ...

  5. C#/ASP.NET MVC微信公众号接口开发之从零开发(四) 微信自定义菜单(附源码)

    C#/ASP.NET MVC微信接口开发文章目录: 1.C#/ASP.NET MVC微信公众号接口开发之从零开发(一) 接入微信公众平台 2.C#/ASP.NET MVC微信公众号接口开发之从零开发( ...

  6. C#/ASP.NET MVC微信公众号接口开发之从零开发(三)回复消息 (附源码)

    C#/ASP.NET MVC微信接口开发文章目录: 1.C#/ASP.NET MVC微信公众号接口开发之从零开发(一) 接入微信公众平台 2.C#/ASP.NET MVC微信公众号接口开发之从零开发( ...

  7. ASP.NET程序读取二代身份证(附源码)

    原文:ASP.NET程序读取二代身份证(附源码) 一般来说winform应用程序解决这个问题起来时很容易的,web应用程序就麻烦一点了. 这里我说说我的解决思路: 一.你必要有联机型居民身份证阅读器一 ...

  8. 【转】精选十二款餐饮、快递、票务行业微信小程序源码demo推荐

    微信小程序的初衷是为了线下实体业服务的,必须有实体相结合才能显示小程序的魅力.个人认为微信小程序对于餐饮业和快递业这样业务比较单一的行业比较有市场,故整理推荐12款餐饮业和快递业微信小程序源码demo ...

  9. 微信小程序版博客——开发汇总总结(附源码)

    花了点时间陆陆续续,拼拼凑凑将我的小程序版博客搭建完了,这里做个简单的分享和总结. 整体效果 对于博客来说功能页面不是很多,且有些限制于后端服务(基于ghost博客提供的服务),相关样式可以参考截图或 ...

  10. Flask开发VIP版HttpServer #华为云·寻找黑马程序员#

    欢迎添加华为云小助手微信(微信号:HWCloud002 或 HWCloud003),输入关键字"加群",加入华为云线上技术讨论群:输入关键字"最新活动",获取华 ...

随机推荐

  1. 记一次windows10电脑连上wifi无法上网的解决问题

    前言 今天下午同学的电脑能连上wifi,但是却上不了互联网 开始思考 首先想到的肯定是WiFi驱动问题,但是wifi能连上大部分的原因可能就不是驱动问题了,为了彻底排除这个因素,我用到了我的usb网卡 ...

  2. NET 6 实现滑动验证码(三)、接口

    题外话,有网友说,这玩意根本很容易破解,确实是这样.但验证码这东西,就跟锁子很类似,防君子不防小人.验证码的发明其实是社会文明的退步.因为它阻碍了真正的使用者,却无法阻挡别有用心的人.但又有什么办法呢 ...

  3. 根据经纬度算UTM带号

    1.  UTM (Universal Transverse Mercator)坐标系是由美国军方在1947提出的.虽然我们仍然将其看作与"高斯-克吕格"相似的坐标系统,但实际上UT ...

  4. TornadoFx的TableView组件使用

    原文: TornadoFx的TableView组件使用 - Stars-One的杂货小窝 最近慢慢地接触了JavaFx中的TableView的使用,记下笔记总结 使用 1.基本使用 TornadoFx ...

  5. 浏览器内存漫游解决方案(js逆向)

    //浏览器内存漫游解决方案(js逆向) //原理通过ast把所有的变量,参数中间值进行内存的存储 //搜索AST-hook,进入github //现在github的库下载下来 //anyproxy n ...

  6. SpringBoot向Excel模板中写入数据并下载 (无需获取file对象及模板绝对路径)

    之前用获取模板路径的方式测试没问题打包后就有问题了 莫名出现一个! 找了很多教程尝试无果 最终使用下面这个方式 无需获取file对象以及模板路径的方式进行写入下载 (那个设置浏览器编码没有测试不知道能 ...

  7. plsql developer切换用户

    方法1: 1.双击plsql developer桌面软件图标启动软件 2.在连接窗口中填写连接信息,连接数据库 3.在新建窗口下拉选项中,选择命令窗口功能 4.在工作区内会出现当前用户连接数据库的窗口 ...

  8. 使用JsonConverter处理上传文件的路径

    场景 我们上传一个文件,把文件保存到服务器上,会有一个明确的物理路径,由于需要从前端访问这个文件,还需要web服务器中的一个虚拟路径.这个虚拟路径的存储会有一个问题,我们应该在数据库里存什么?是带域名 ...

  9. 写一个 Markdown 博客客户端

    这个"伪需求"是最近才想到的. 关于文章管理的想法,说来话长.我最初是在 CSDN 写技术文章,就用网页上的编辑器.后来在 CppBlog 写,用上了 Windows Live W ...

  10. 数据结构与算法 -> 大顶堆与小顶堆

    一.大顶堆 大顶堆是一种数据结构,它是一颗完全二叉树,并且满足以下性质: 每个节点的值都大于或等于它的子节点的值 因此,大顶堆的根节点(也称为堆顶)总是最大的元素 二.小顶堆 小顶堆也是一种数据结构, ...