前言

2018年下半年要说最火的产品莫过于音遇了,上线短短一连个月,估值将近2亿美金,他的产品也被各大公司所模仿借鉴,包括我们公司?!接下来我将说说这款APP的直播间的解决方案,以供大家参考!

也算是对我上一份工作的一个总结吧!?

产品分析

a.音视频处理

游戏直播间是一种在线推流和拉流的操作,目前主要的推流和拉流的方式有常见的RTMP和RTC两种;

RTMP: 基于 TCP 的标准协议,与 CDN 架构兼容,对客户来说在现有单向直播架构上,接入成本比较低,但是缺点也多,回音、传输延时大、耗费CPU等资源等等,但是便宜;

RTC:降低了音视频通信的接入门槛,而且用户体验比较好,最主要的是没有延迟;缺点就是价格昂贵(如果你公司不差钱就当我没说?);

但是如果是普通的视频直播什么的使用RTMP也没啥问题,关键是这种抢答类的产品对实时性要求比较高,肯定要选择RTC了!

目前RTC如果使用第三方收费都不便宜,我们公司的产品用的是七牛云存储的RTC直播间,2019年第一版刚出来,价格还很便宜?。

相关:《七牛实时音视频云》

b.指令下发

如果想让前端与后端实时通讯,进行数据传输和指令交互,就需要做socket长连接,这样即需要后台开发人员对服务器进行配置还需要公司出资购买新的服务器,一切为了省钱......

这样我就想到了使用IM即使聊天来代替socket长连接的实时交互,关键是在游戏直播间还必须用到IM聊天系统;具体的实现思路是在游戏直播间由服务器扮演管理员的角色,对房间的所有人所在的群组发送管理员消息,当然所以得管理员消息我们会进行筛选和过滤,这样就不会暂时在聊天界面上了,还有一些答题信息或者答题结果我们都可以以data或字典的形式放在自定义的字段里面,代码如下:

WEAKBLOCK;[TXIMTools manager].getNewMessages = ^(TIMMessage *meg) {//[2019-03-18 16:03:00][status:2 sender=255762] [TIMTextElem=text:准备好了吗!快点开始吧!]for (RAUserModel *model in self.userArray) {if([model.userId intValue] == [meg.sender intValue]){[weakSelf.chatView addOneTXIMChatMeg:meg number:model.number];break;}}};
- (void)getAdminOrder:(NSInteger)code dataDict:(NSDictionary *)dataDict{WEAKBLOCK;if(code == 2000){//游戏开始 gameRoom_isStratGame = YES;[RAMatchStateView showRAReadyStartViewFinished:^{NSLog(@"游戏开始");}];[self upLoadUserArrayWithGameRoom:dataDict code:code];[self.engine joinRoomWithToken:_currentUserModel.rtcToken userData:nil];self.topView.hidden = NO;self.likesBtn.hidden = NO;}else if (code == 2001){//游戏出题 gameRoom//...此处省略2000行代码...}else if(code == 2002){//用户抢答(谁抢到了) "id", "number", "name", "gender", "type"}else if(code == 2003){//通知哪个用户抢到 "id", "number", "name", "gender", "type"_answerUserInfors = dataDict;//答题者信息[self.subjectView hideRASubjectView];[self.robButton hideRARobButton];[self.matchStateView refreshAnswerStateView:GetChanceType number:dataDict[@"number"] name:dataDict[@"name"]];if([dataDict[@"id"] integerValue] == [_currentUserModel.userId integerValue]){//当前用户抢到了 等待答题[MBProgressHUD SHOWPrompttextNeedClose:@"等待答题···"];}}else if(code == 2004){//全军覆没 返回null[self.subjectView hideRASubjectView];[self.robButton hideRARobButton];[self.matchStateView refreshAnswerStateView:NoOneAnswerType number:nil name:nil];_answerUserInfors = nil;}else if(code == 2006){//答题成功了 返回null//...此处省略2000行代码...}else if(code == 2007){//答题打错了 返回null//...此处省略2000行代码...}else if(code == 2008){//游戏结束 gameRoom[self upLoadUserArrayWithGameRoom:dataDict code:code];[self.subjectView hideRASubjectView];[self.matchStateView hideAnswerStateView];[self gameOver];_answerUserInfors = nil;}else if(code == 2009){//加入房间 room[self analysisRoomDataDict:dataDict];}else if(code == 2010){//退出房间 room[self analysisRoomDataDict:dataDict];}else if(code == 2011){//邀请好友进入房间 "id"(用户ID), "number", "name", "type"(用户类型), "gameType", "gradeDesc", "articleType", "roomId"//在base处理}else if(code == 2012){//淘汰用户 返回 "id", "number", "name" 用户Id 用户number 用户名称NSString *number = [NSString stringWithFormat:@"%@",dataDict[@"number"]];NSString *name = dataDict[@"name"];[self.subjectView hideRASubjectView];[self.matchStateView refreshAnswerStateView:DieOutType number:number name:name];}else if(code == 2013){//等待下一题[self.subjectView hideRASubjectView];[self.matchStateView refreshAnswerStateView:AnswerNextQuestionType number:nil name:nil];[MBProgressHUD HIDEPrompttextByClose];_answerUserInfors = nil;}else if(code == 2014){//谁接背 返回 "id", "number", "name" 用户Id 用户number 用户名称//...此处省略2000行代码...}else if(code == 2015){//会 进入答题流程 返回 "id", "number", "name" 用户Id 用户number 用户名称//保持状态}else if(code == 2016){//不会 返回 "id", "number", "name" 用户Id 用户number 用户名称//保持状态}else if(code == 2018){//抢背开始//...此处省略2000行代码...}else if(code == 2019){//用户答题指令 返回 "id", "number", "name" 用户Id 用户number 用户名称 开始答题[self answerAndStopAnswer:dataDict];}else if(code == 2020){//取消匹配 room//在WaitingGameRoomViewController界面处理UI[self analysisRoomDataDict:dataDict];}else if(code == 2021){//匹配中 room[self showMatchingView];}else if(code == 2022){//匹配成功 gameRoom[self upLoadUserArrayWithGameRoom:dataDict code:code];self.headView.hidden = YES;self.inviteBtn.hidden = YES;self.quickStartBtn.hidden = YES;}else if(code == 2023){//用户准备 返回 "id", "number", "name" 用户Id 用户number 用户名称[self userReadyOrUnReady:dataDict[@"id"] isReady:YES];}else if(code == 2024){//用户取消准备 返回 "id", "number", "name" 用户Id 用户number 用户名称[self userReadyOrUnReady:dataDict[@"id"] isReady:NO];}else if(code == 2025){//用户送礼 giveUserNumber userNumber pic[self.giftListView addOneSentGiftMeg:dataDict];}else if(code == 2026){//用户被踢出房间(只有被踢出的人才能收到这个消息) roomId - (void)kickoutUser:(NSString *)userId;[self.engine kickoutUser:_currentUserModel.userId];[ZFJReciteAlertView showAlertViewSureBtnWithTitle:@"您已被房主移出房间!" selectedIndex:^(NSInteger index) {[weakSelf leaveRoom];}];}else if(code == 2027){//开始推流 返回答题用户 返回 "id", "number", "name" 用户Id 用户number 用户名称//只有答题者才可以推流if([dataDict[@"id"] integerValue] == [_currentUserModel.userId integerValue]){[self.engine publishAudio];}}
}

注明:以上只提供逻辑指令处理,不会给出详细数据处理或者动画代码!

语言识别

我们需要将用户说的话识别为文字(汉子或英语),然后与数据库的答案进行对照,然后给出得分。这里的语言识别当然推荐使用科大讯飞了,比较赫赫有名的走在语言识别前端的技术(收费高);但是我们产品用的是百度语言识别,为什么呢?免费、免费、免费,重要的事情我说三遍!!!

一开始想把百度语言识别的SDK直接集成在工程中,这样识别的效率高、耗时短,但是,有两点不好的地方,对于我这中优化狂魔所不能忍的是:

a.语言识别的库占用很大一部分内存,是API的包增加了20多M;

b.我们还要对语音进行保存,这样在一边识别的时候我们还要一边录音,导致的问题就是,耗内存资源;

所以经过考虑,我们把百度语言识别交给服务端的小伙伴来搞,前端只需要录音就可以了,然后把MP3文件直接传给后端,后端小伙伴在指令里面给出结果!So easy!(妈妈再也不用担心我的包太大了)?

音频处理

这个功能我们需要经常使用AVAudioRecorder,比如录音、播放领读、播放动画音效等等;AVAudioRecorder频繁创建肯定会影响APP性能,所以我把AVAudioRecorder封装起来丢进单利里面;封装的方法包含录音和播放的功能,代码如下(仅提供思路):

@interface RecordOperation : NSObject//-----------------------------录音相关-----------------------------/**普通MP3录音@return self*/
- (instancetype)init;/**开始录音*/
- (void)startRecord;/**结束录音返回caf@param scuBlock caf回调音频文件地址*/
- (void)stopRecord_Caf_ScuBlock:(void(^)(NSString *urlPath, CGFloat audioSeconds))scuBlock;/**获取录音声波状态@param averagePower 声波值回调*/
- (void)getAveragePowerForChannel:(AveragePower)value;/**播放录音的文件*/
- (void)playListenningRecognition;/**是否正在录音*/
@property (nonatomic,assign) BOOL isRecording;//-----------------------------播放相关-----------------------------/**播放音频文件@param urlStr 音频文件地址@param duration 音频文件总时长@param playCompleted 播放完成回调*/
- (void)playVoiceBubbleWithUrlStr:(NSString *)urlStr duration:(VoiceInforsBlock)duration playCompleted:(PlayCompleted)playCompleted;/**获取播放音频文件信息@param currentTime 播放时间@param progress 进度*/
- (void)getVoiceBubbleCurrentTime:(VoiceInforsBlock)currentTime progress:(VoiceInforsBlock)progress;/**停止播放音频文件*/
- (void)stopPlayVoiceBubble;@end

控件封装

像这种交互性比较强的产品,各种题目信息或者答题状态还有试图动画也肯定必不可少了,这就需要我们把相同的控件和功能进行打包封装,以减少C的代码,不会使Controller过于臃肿,也更利于代码的刻度与赏心悦目的赶脚!

下面的代码是题目状态信息的过渡动画,仅供参考:

@interface RAMatchStateView : UIView/**正在匹配初始化@return self*/
- (instancetype)initReadyToStartView;/**显示匹配成功*/
- (void)showMatchCompletion;/**准备开始 1 2 3 GO@param finished 完成回调*/
+ (void)showRAReadyStartViewFinished:(FinishCountDownBlock)finished;/**答题状态初始化@param frame 坐标@return self*/
- (instancetype)initAnswerStateView:(CGRect)frame;/**刷新控件答题状态@param stateType 状态类型@param number 用户ID@param name 用户name*/
- (void)refreshAnswerStateView:(AnswerStateType)stateType number:(NSString *)number name:(NSString *)name;/**隐藏控件答题状态*/
- (void)hideAnswerStateView;@end

产品展示

结束语

欢迎各位大神补充!

APP在线抢答解决方案(RTC直播间抢答或者抢背唱歌)相关推荐

  1. ​周锦民:腾讯在线教育视频互动直播间技术实践

    本文来自腾讯云技术沙龙,本次沙龙主题为在线教育个性化教学技术实践 演讲嘉宾:周锦民 | 2011年毕业进入腾讯, 现任在线教育部在线教育后台中心高级工程师,多年linux后台开发工作经验,目前主要负责 ...

  2. 【php】基于Xajax的在线聊天室、直播间

    关于php的Xajax到底是什么,这里不再介绍,详情可以看我<[php]Xajax Helloworld>(点击打开链接)与<[php]注册系统和使用Xajax即时验证用户名是否被占 ...

  3. 小程序直播间页面路径怎么访问直播间_以小程序为例,在线教育产品的直播间有哪些功能设计?...

    直播兴起已经很久,在线教育玩直播的也有很多.本文作者从工作实践出发,结合案例分享了小程序直播间都做了哪些功能设计,为什么要这么设计,及对设计的复盘. 一.直播间都需要搭建哪些功能模块? 在收集了业务的 ...

  4. 杨婷:腾讯云在线教育解决方案分享

    本文来自腾讯云技术沙龙,本次沙龙主题为在线教育个性化教学技术实践 演讲嘉宾:杨婷,腾讯高级产品经理.2010年重庆大学通信工程毕业,6年音视频相关产品从业经验.先后负责过视频云平台.视频CDN.直播点 ...

  5. 直播带货源码APP开发/直播间+短视频推广+社区朋友圈解决方案

    直播带货商城系统可以相结合多元化的网络直播模式进行营销推广,例如网络直播+渠道分销.短片视频+直播带货.网络直播+人物角色返利这些.个人开店.网络主播都可以借助网络直播商城系统直播,分享至微信圈,好朋 ...

  6. 如何打造在线直播间(技术贴)

    背景 当下视频直播如此红火,打造一个在线直播间涉及到哪些技术呢? 视频直播由主播的直播端以及观众的观看端组成.一个简单的观看端最起码应包含播放器以及聊天室.下面就围绕这两大模块来讲述相关技术. 视频直 ...

  7. 七月Z星月度速览 | Milvus 源码解析重磅来袭、学术直播间开播、Milvus 社区在线答疑会重启、智能问答机器人上线……...

    #July Z星月度速览 · 小 Mil 来了!Milvus 智能问答机器人上线 · Zilliz 合伙人.工程总监栾小凡与社区分享首期 Milvus 底层源码架构解析 · Milvus 社区发起首期 ...

  8. 在线直播间和视频追帧【转载】

    背景 当下视频直播如此红火,打造一个在线直播间涉及到哪些技术呢? 视频直播由主播的直播端以及观众的观看端组成.一个简单的观看端最起码应包含播放器以及聊天室.下面就围绕这两大模块来讲述相关技术. 视频直 ...

  9. 短视频小视频直播app开发定制解决方案

    一.直播APP的市场前景 随着智能移动手机端的普及,人们对于线上的娱乐的要求越发感兴趣,很多互联网电商平台也将直播APP作为销售的主战场之一.将线上与线下的方式相结合才能更好的促进企业的发展.当然对于 ...

最新文章

  1. MapReduce原理与设计思想
  2. 067 Add Binary 二进制求和
  3. python 多维数组删除重复
  4. python介绍和用途-Python字典简介以及用法详解
  5. c调用易语言串口,易语言串口API源码
  6. 经营升级渐成影院运营主课题,怎样才能交出技术改造好答卷?
  7. Linux RH5平台下使用Oracle ASM创建数据库
  8. Facebook开源计算机视觉目标检测平台Detectron
  9. CIRCOS增加热图、点图、线图和区块属性
  10. ajax ssm 页面跳转_Shiro 教程,Ajax请求拦截跳转页面方案
  11. ANSI,Unicode,UTF-8网页编码的区别【转】
  12. mysql -d -e_mysql常用函数
  13. SOME/IP不等同于SOA,CommonAPI-RPC通信和vsomeip基于消息通信
  14. labview高级视频150讲下载_视频剪辑篇|讲真的,这些软件素材资源我真舍不得分享!(附下载包)...
  15. qt 导出word中插入图片
  16. python中除以0的处理方法
  17. 排序算法之python实现(上)
  18. 5G商用元年开启万亿市场, 25G服务器端口出货量大幅增长
  19. phpmyadmin爆破脚本练习
  20. flash的读写擦除

热门文章

  1. 晓月_【斗战神学习四十】金山寺
  2. 疯狂python讲义学习笔记——中十章完结
  3. 如何使用javascript制作一个网页端3D贪吃蛇游戏(附源码及链接)
  4. 导图解文 从梦想到财富(39)正确的创业方向,都落在3个必然趋势中
  5. 怎么能看出一个人开车水平高低?
  6. java后端秋招面经
  7. c语言窄字符转换为宽字符,将窄字符串转换为宽字符串
  8. 深度学习笔记(6)BatchNorm批量标准化
  9. 微软赵立威:云计算技术是移动互联网开发核心
  10. Dell电脑 U盘启动盘 安装ubuntu