首页 > 其他分享 >技术实战 —— 快速实现语聊房搭建

技术实战 —— 快速实现语聊房搭建

时间:2023-06-13 13:04:54浏览次数:33  
标签:实战 self 房间 用户 语聊 声浪 ID 搭建


语音相比文字图片更丰富,比视频又更简便,是天然的社交工具。以95后为代表的Z世代用户,在微信、QQ、微博等主流社交工具以外,更愿意尝试基于不同兴趣相对小众的社交工具。ZEGO 即构科技推出语聊房解决方案,帮助客户快速搭建语聊房。本次分享,我们邀请到了 即构科技交付解决方案专家 JIN 。他向我们分享了线上社交以及语聊房的发展、玩法,并详细解析如何快速搭建语聊房,提供稳定、低延时,高品质的线上互动体验。

文 | JIN

整理 | LiveVideoStack

大家晚上好,我是即构科技解决方案专家 JIN。很荣幸担任语聊房专题的讲师,今晚的主题就是语聊房的搭建,我将从三个方面为大家讲述,包括语聊房的衍生玩法及发展,ZEGO语聊房解决方案,以及语聊房搭建实战。

01

语聊房的衍生与玩法

首先进入第一部分。

技术实战 —— 快速实现语聊房搭建_编程语言

科技改变生活,在零几年诺基亚盛行的时候,大家可以通过QQ发送文字消息进行聊天,随着智能手机的兴起,即时通讯、短视频、视频直播、语聊等逐渐火热。而今晚的主题就是语聊。

技术实战 —— 快速实现语聊房搭建_android_02

近几年语聊发展的相当火爆,尤其是年前的Clubhouse火了很长一段时间,具体火到什么程度,可以看这个图。这是2014-2019年中国语聊房行业用户付费率及付费 ARPPU 值的统计图,付费率指的是100人中,有多少人愿意付费,ARPPU 值指的是付费的人中平均付费多少钱。在2014年,100人中只有3-4人愿意付费,而这3-4人平均愿意付费64.8元,到了2019年已经涨到了161.5元,付费意愿人数比例也从之前的3-4人,提升到15人。

技术实战 —— 快速实现语聊房搭建_android_03

上图数据是2021年8-10月Z世代用户在语聊行业APP活跃度,左边刻度单位为“万人”。Soul是在语聊行业中比较火的APP,紫色代表的是十月份的活跃度,大概有1993万人在线,而8月有2375万人在线,人数相当多,这只是一家APP的数据。

技术实战 —— 快速实现语聊房搭建_java_04

上图展示的是今年8-10月Z世代用户在语聊行业APP在线时长,数据来源于即构的后台统计,Soul8月总计在线时长达到了1017336分钟。从以上三组数据可以看出语聊房是非常火爆的,它为泛娱乐行业APP带来了很大的收益,同时也增加了用户粘性及在线时长。

技术实战 —— 快速实现语聊房搭建_编程语言_05

语聊房比较常见的形式是1V1聊天房,在一些相亲类的APP里,比较常见的是提供1V1的语聊服务,不过这些服务都是要付费的。

技术实战 —— 快速实现语聊房搭建_android_06

第二种形式是多人语聊房,这种玩法就比较多了,首先是多人纯语聊,在线会议是比较常见场景,第二种是游戏开黑,第三种是赛事直播,一起观看赛事直播发表评论,第四种也是比较常见的一起看电影,第五种pia戏,就是多人根据剧本台词,进行实时的配音扮演,如右图所示。

技术实战 —— 快速实现语聊房搭建_编程语言_07

第三种形式是语音电台,可以理解为主播直播,用户可以对他进行打赏。

技术实战 —— 快速实现语聊房搭建_大数据_08

第四种类型是KTV玩法,在语聊房技术上加上K歌,可以一边唱歌一边聊天进行打赏。

02

ZEGO语聊房解决方案

第二部分是即构提出的语聊房解决方案。

技术实战 —— 快速实现语聊房搭建_编程语言_09

主要分为三大模块。

第一模块多人语音聊天,我们在里面做了四种适配,第一种是对接一线网络运营商,节点资源丰富,无上限扩大容量。第二种是针对回声消除进行的算法优化。第三种是降低端到端延迟,让语聊更快。第四种是适应多种复杂网络,同时兼容5000+安卓机型。

技术实战 —— 快速实现语聊房搭建_大数据_10

第二个模块是音乐播放,单纯语音聊天比较单调,通过播放背景音乐或者气氛音效提升活跃度。我们支持播放MP3、MP4格式的背景音乐文件,支持播放器将播放的音频混入推流中,同时支持音效播放器的音频文件。

技术实战 —— 快速实现语聊房搭建_android_11

第三个模块是支持APP后台保持,切换到游戏实现语音开黑。

技术实战 —— 快速实现语聊房搭建_java_12

以上就是即构解决方案的三大模块,接下来介绍一下我们的优势,首先是多人上麦语音聊天以及上下麦平滑切换,其次是支持实时变声、立体声、气氛音效、混响等多种音频效果,第三是支持弹幕、点赞、送礼等多种消息类型,第四是先进的不连续发射(DTX)和语音活动检测(VAD)技术,这两个技术会检测当前用户是否在说话,如果正在说话,我们将他的声音录制下来推出去,如果不说话的话,我们会发空白帧,减少用户的流量。

技术实战 —— 快速实现语聊房搭建_android_13

除此之外,还有各种配套的功能支持,这里有音效播放器、媒体播放器、混音、混响、声浪与音频频谱、媒体次要信息以及房间信令。声浪与音频频谱用来展示当前谁在说话与频域分量信息,媒体次要信息属于H.264中的一个类型,用来发用户的自定义消息。

03

语聊房搭建实战

第三部分进入我们的语聊房搭建实战环节。

技术实战 —— 快速实现语聊房搭建_编程语言_14

首先,介绍一下我们语聊房的技术架构。

语聊房把用户分为两种,一种是麦上用户,一种是麦下观众。对于麦上用户来说,A连麦者需要推出自己了流A同时再去拉B的流,B连麦者也是一样的,在上麦时将自己的流推出去,推到服务器,同时将A的流拉过来,这时A和B就可以进行语音互动。麦下的用户只需要拉A和B的流收听即可,麦下的观众可以有很多个。最右边的混流服务可以根据业务需求自行选择,有需要的可以用,没有需要就可以不用,混流可以将A和B的流混成一条流,转推到CDN,观众再从CDN拉流过来,这也是节省成本的一种方式。

技术实战 —— 快速实现语聊房搭建_人工智能_15

接下来我们讲一下语聊房的集成(代码部分)。

由于本人是iOS开发,接下来会给各位展示下用OC实现语聊房集成。可以参考Zego音视频集成文档。 (https://doc-zh.zego.im/article/196)

- (void)createEngine{
    //创建引擎
    ZegoEngineProfile *profile = [[ZegoEngineProfile alloc] init];
    profile.appID = kKTVAppID;
    profile.appSign = kKTVSign;
    profile.scenario = ZegoScenarioGeneral;
    self.engine = [ZegoExpressEngine createEngineWithProfile:profile eventHandler:self];
    //设置音频编码配置
    ZegoAudioConfig *config = [[ZegoAudioConfig alloc] initWithPreset:ZegoAudioConfigPresetStandardQuality];
    config.channel = ZegoAudioChannelMono;
    config.codecID = ZegoAudioCodecIDLow3;
    [self.engine setAudioConfig:config channel:ZegoPublishChannelMain];




    //设置监听声浪回调
    [self.engine startSoundLevelMonitor];
}


首先需要创建引擎,创建引擎的时候需要设置一个配置,配置是ZegoEngineProfile对象,ZegoEngineProfile对象需要设置三个参数:appid、appsign、scenario。appid和appsign可以到zego官网申请获得。






这里需要重点讲解下scenario这个参数。


/// Application scenario.
typedef NS_ENUM(NSUInteger, ZegoScenario) {
    /// General scenario
    ZegoScenarioGeneral = 0,
    /// Communication scenario
    ZegoScenarioCommunication = 1,
    /// Live scenario
    ZegoScenarioLive = 2
};

scenario这个参数是个枚举值,通过SDK接口可以看到有三个值。第一个General适用在对音质要求高的场景,例如在线KTV。设置这个参数后SDK内部会关闭系统的回声消除,我们也称这个配置为媒体音量模式。第二个和第三个枚举值设置后SDK内部会开启系统回声消除,我们称为通话音量模式,通话音量的效果就跟使用手机的电话通话时候的效果一样。因为是使用回声消除算法会对音质有损伤。一般使用在语聊场景,在线教育场景。语聊房场景下使用Communication即可。

接下来咱们设置下音频编码配置,先初始化一个ZegoAudioConfig对象,然后咱们设置下音频码率为48k,使用默认参数即可。然后设置下声道数为Mono,在语聊场景下人声使用双声道有点浪费带宽,也不需双声道的效果。音频编码格式为Low3,可以降低端到端延迟,提高用户体验。最后设置下音频配置。

在语聊房中咱们通常会需要在麦位上展示声浪,这里需要打开声浪的开关。声浪分为本端声浪和远端声浪。这里有两个回调可以处理声浪。这两个回调接口中都带有soundLevel参数,这个表示音量的大小,可以根据音量大小去决定是否展示声浪。

//本端声浪
- (void)onCapturedSoundLevelUpdate:(NSNumber *)soundLevel {
    if ([self.delegate respondsToSelector:@selector(onCapturedSoundLevelUpdate:)]) {
        [self.delegate onCapturedSoundLevelUpdate:soundLevel];
    }
}
//拉流声浪
- (void)onRemoteSoundLevelUpdate:(NSDictionary<NSString *,NSNumber *> *)soundLevels{
    if ([self.delegate respondsToSelector:@selector(onRemoteSoundLevelUpdate:)]) {
        [self.delegate onRemoteSoundLevelUpdate:soundLevels];
    }
}






接下来咱们需要登录房间。登录的时候需要设置用户信息,用户信息包括用户ID和用户昵称,以及房间号。






- (void)joinRoomWithRoomID:(NSString *)roomID userID:(NSString *)userID userName:(NSString *)userName{
    ZegoUser *user = [ZegoUser userWithUserID:userID userName:userName];
    ZegoRoomConfig *config = [ZegoRoomConfig defaultConfig];
    self.roomID = roomID;
    [[ZegoExpressEngine sharedEngine] loginRoom:roomID user:user config:config];
}

登录房间后怎么判断登录成功了?咱们需要在房间的回调中进行处理,这个回调是onRoomStateUpdate。这个回调中有个房间状态枚举值,对应有三种状态。

/// Room state.
typedef NS_ENUM(NSUInteger, ZegoRoomState) {
    /// Unconnected state, enter this state before logging in and after exiting the room. If there is a steady state abnormality in the process of logging in to the room, such as AppID and AppSign are incorrect, or if the same user name is logged in elsewhere and the local end is KickOut, it will enter this state.
    ZegoRoomStateDisconnected = 0,
    /// The state that the connection is being requested. It will enter this state after successful execution login room function. The display of the UI is usually performed using this state. If the connection is interrupted due to poor network quality, the SDK will perform an internal retry and will return to the requesting connection status.
    ZegoRoomStateConnecting = 1,
    /// The status that is successfully connected. Entering this status indicates that the login to the room has been successful. The user can receive the callback notification of the user and the stream information in the room.
    ZegoRoomStateConnected = 2
};

咱们首先需要判断状态是否为ZegoRoomStateConnected,然后在判断errorCode是否为0。这个时候就是登录房间成功。如果状态为ZegoRoomStateConnected但是errorCode不为0,表示当前情况为掉线重连成功,errorCode会显示对应的错误码。退出房间也是一样的道理。

- (void)onRoomStateUpdate:(ZegoRoomState)state errorCode:(int)errorCode extendedData:(nullable NSDictionary *)extendedData roomID:(NSString *)roomID {
    if (state == ZegoRoomStateConnected && errorCode == 0) {
        if ([self.delegate respondsToSelector:@selector(onLoginRoom)]) {
            [self.delegate onLoginRoom];
        }
    }
}

登录房间成功后需要拉流。一般情况下,在语聊房中除了房主其他用户登录房间后都不会马上推流,需要上麦后才推流。房主登录房间后可以在onRoomStateUpdate回调中推流,推流接口为:

- (void)startPublishingStream:(NSString *)streamID channel:(ZegoPublishChannel)channel;

拉流接口为:

- (void)startPlayingStream:(NSString *)streamID canvas:(nullable ZegoCanvas *)canvas;

这里需要说明下,ZegoSDK是按照流去设计接口。其他市面上的厂商的SDK设计理念不一样,他们是按照角色和场景SDK内部就实现了推拉流。使用ZegoSDK需要手动去推拉流。推流时机一般是在登录成功后或者上麦成功后。拉流时机为登录房间后且在流变更回调中去拉流。

流变更回调为onRoomStreamUpdate。

这个回调用有ZegoUpdateType枚举值,对应的是流新增和流删除。当某个用户推流成功后房间内其他人会触发流新增回调,当某个用户停止推流后房间内其他人会收到流删除回调。所以在这里实现拉流的操作即可。

- (void)onRoomStreamUpdate:(ZegoUpdateType)updateType streamList:(NSArray<ZegoStream *> *)streamList extendedData:(nullable NSDictionary *)extendedData roomID:(NSString *)roomID {
    if (updateType == ZegoUpdateTypeAdd) {
        for (ZegoStream *stream in streamList) {
            [self.playStreams addObject:stream.streamID];
            [self.engine startPlayingStream:stream.streamID canvas:nil];
            if ([self.delegate respondsToSelector:@selector(onUserJoinedWithStreamdID:)]) {
                [self.delegate onUserJoinedWithStreamdID:stream.streamID];
            }
        }
    }else if(updateType == ZegoUpdateTypeDelete){
        for (ZegoStream *stream in streamList) {
            [self.playStreams removeObject:stream.streamID];
            [self.engine stopPlayingStream:stream.streamID];
            if ([self.delegate respondsToSelector:@selector(onUserLeavedWithStreamdID:)]) {
                [self.delegate onUserLeavedWithStreamdID:stream.streamID];
            }
        }
    }
}

以上的功能实现集合在一起就可以搭建一个简单的语聊房。

如果需要播放音乐可以使用媒体播放,接下来咱们创建个媒体播放器。

self.mediaPlayer = [[ZegoExpressEngine sharedEngine] createMediaPlayer];

播放之前需要先加载资源,使用loadResource接口,然后调用start播放即可。

以上就是集成语聊房需要用到的基本接口,其他接口可以参考文档集成。

4、常见问题 —— 幽灵麦

接下来咱们聊一聊语聊房场景的问题。

技术实战 —— 快速实现语聊房搭建_java_16

比较常见的坑就是幽灵麦的问题,用户已经不在麦上了,但还能听到他的声音。

针对幽灵麦问题,我们提出了三种解决方案:

  1. 使用Token鉴权:即用户在登入房间时,对其身份进行校验,如果校验不成功,则不允许其进入房间。
  2. 流ID不和用户ID绑定:我们常遇到的场景是会将流ID和用户ID进行绑定,使用用户的ID当做流ID进行推拉流。比如一个用户登录房间A进行聊天,此时直接关闭APP,立即重新登录房间B,并上麦推拉流。由于流ID和用户ID是一样的,我们很难发现用户是什么时候掉线的,并且在用户掉线时,会自动尝试重连,重连有90s的时间,如果在这个时间内产生了上述操作,那么,在之前房间A拉的流没有停止,所以还是能听到他的声音。如果使用流ID不和用户ID绑定的方案,每次登录房间后推流的ID不一样,即使上一次的流链接还存在,但是没有数据,也就不会出现幽灵麦的问题。
  3. 麦位管理配合流变更通知:常用的麦位管理会建议用户使用第三方麦位管理,同时为避免不稳定,可以配合流新增的回调做处理。如果我们这里流触发新增了,再更新UI显示在麦上,如果流没有新增,即使第三方麦位管理显示已经成功上麦,说话也不成功,删除下麦也是同理。

以上是本次分享的全部内容,谢谢大家。

标签:实战,self,房间,用户,语聊,声浪,ID,搭建
From: https://blog.51cto.com/u_13530535/6468970

相关文章

  • 一对一直播源码平台搭建的关键条件,成败在此。
     网络时代的前进,人们对直播也有了新的要求,对于观众们来说,大多数观众更喜欢只让自己和主播进行交流,只有不仅仅能增加私密性,而且还能和自己喜欢的主播更加亲近真实,像是面对面一样;而对于主播而言,大部分主播都想让自己轻松许多,并且收益更高。而随着直播源码平台的发展,一对一直播源码......
  • linux系统nfs搭建-cnblog
    Linux系统nfs搭建首先介绍一下NFS:​ NFS(NetworkFileSystem)即网络文件系统,是FreeBSD支持的文件系统中的一种,它允许网络中的计算机之间通过TCP/IP网络共享资源。在NFS的应用中,本地NFS的客户端应用可以透明地读写位于远端NFS服务器上的文件,就像访问本地文件一样。1、虚拟机nfs环......
  • 搭建storm集群(apache-storm-0.9.5.tar.gz)
    //搭建storm集群(apache-storm-0.9.5.tar.gz)#bycoco#2015-07-15前期准备:3台服务器:192.168.8.94 192.168.8.95192.168.8.96去storm官网下载响应版本的软件包:http://storm.apache.org/downloads.html在这里下载的是:wg......
  • 了解 Kubernetes (k8s) 概念,搭建一套集群。
    ......
  • Java 实战介绍 Cookie 和 Session 的区别
    HTTP是一种不保存状态的协议,即无状态协议,HTTP协议不会保存请求和响应之间的通信状态,协议对于发送过的请求和响应都不会做持久化处理。无状态协议减少了对服务压力,如果一个服务器需要处理百万级用户的请求状态,对服务器的压力无疑的是巨大的。无状态的HTTP由于其简单和易用性......
  • 医学生的人工智能实战课
    医学生的人工智能实战课-初阶(Rversion)PracticalAIcourseformedicalstudents教学大纲SyllabusI准备工作R和Rstudio安装Quarto和RMarkdownPython和JupyterLab包的安装与加载II数据启蒙数据和数据类型数据结构整洁数据TidydataTidy流派和其他流......
  • Spring的环境搭建的IOC
    1、Spring的简单组成bean的生命周期的管理:java对象的创建,使用,销毁等轻量级:使用简单容器:spring可以管理对象,创建好对象,放入spring容器,容器就是存放对象的组成部分:SpringCore、SpringAOP、SpringORM、SpringDAO、SpringContext、SpringWeb和SpringWeb......
  • MySQL-MHA搭建
    1、测试环境目前MHA主要支持一主多从的架构,要搭建MHA,要求一个复制集群中必须最少有三台数据库服务器,一主二从,即一台充当master,一台充当备用master,另外一台充当从库.一主两从的环境,通过GTID方式配置主从复制同步环境用途IP地址安装软件MySQL版本主库db01192.168.3......
  • vulhub靶场搭建,以及使用方法
    如何安装vulhub靶场备份文件(如果没有重要的东西,就非必要)cp/etc/yum.repos.d/CentOS-Base.repo/etc/yum.repos.d/CentOS-Base.repo.bak下载阿里云覆盖原文件curl-o/etc/yum.repos.d/CentOS-Base.repohttp://mirrors.aliyun.com/repo/Centos-7.repo查看内容确定成功覆盖......
  • 尚医通day01-【项目环境搭建和医院设置详细步骤】(内附源码)
    第01章-项目介绍1、课程介绍项目名称:尚医通预约挂号统一平台项目原型:https://www.114yygh.com北京市预约挂号统一平台项目技术栈:前后端分离后端技术:SpringBoot+SpringCloud+MyBatisPlus+MySQL+MongoDB+Redis+RabbitMQ+Docker+EasyExcel+API远程接口调......