语音连麦聊天室集成介绍

大约 9 分钟

语音连麦聊天室集成介绍

前言

本文将简要分享几个语音聊天室的应用场景,并讲述基于环信 SDK ,实现语音连麦聊天室的步骤。

提示

仅特定的私有化版本SDK支持语聊解决方案. 开发者如有需求,请联系商务咨询。

语音聊天是社交软件必备的功能,语音相比文字图片更丰富,比视频又更简便,是天然的社交工具。除了单纯的1对1语音或视频聊天,在实时音视频技术支持下,很多 APP 已经延伸出多人语聊房、语音电台、语音游戏、私人聊天房、KTV 语聊房等非常丰富的场景。

比如:

  1. 语音电台:是目前很多社交APP的玩法。主播可以在直播间中给听众讲故事、脱口秀、唱歌,多种形式不胜枚举,观众也可以申请上麦与主播聊天互动,在聊天的基础上,加上了背景伴奏音以及通过消息系统来实现的文字消息功能,在这种模式下,可以提高用户的活跃度。

  2. 语音游戏:也是语音聊天室的常见应用场景。支持在狼人杀、剧本杀,王者荣耀及吃鸡等游戏中实现语音开黑,为玩家创建音视频对话实时互动的场景,功能上与语音直播相似,只是在这个频道中,上麦下麦的玩法逻辑有所不同。


Demo

Demo 源码

我们在 Github 已经提供了一套完整的 Demo,在 Demo 的基础上,开发者只需要不到1周的时间,对 UI 和功能做简单修改即可准备测试上线。


实现方案

语音聊天室需要满足的主要功能包括:

  • 支持多人参与语音聊天
  • 支持本地混音
  • 多种连麦模式

要实现一个具备以上功能的语音聊天室,大致可以分为三步:实现语音连麦、支持本地混音,多种连麦模式的设计,基于设计需求,语音聊天室场景化方案的架构图与实现思路如下:
img


实现语音连麦

基于开发者反馈,如果要通过自研的方法实现语音连麦,会存在如下问题:

  • 需要自己部署服务器做好高并发处理;
  • 需要对编解码器优化来解决回声、噪声问题;
  • 需要有成熟的技术方案降低延迟、提高音质;
  • 需要兼容各种网络环境下的用户体验等;

总体来讲,就是需要解决设备端网络中的语音连麦稳定低延时问题与可用性问题。而以上这些问题,环信已为开发者提供成熟的解决方案,并将相关接口封装于SDK 中,让开发者可以简单快速调用集成。

场景需求:观众上麦请求和主播通过上麦申请
在任意模式下,听众进入房间后可以允许发出上麦申请,房主同意后,听众可上麦,用户角色由听众变为了主播,主播要遵循房间模式来实现自己的功能。

实现方案:通过会议属性实现
在语音聊天室 Demo 中,抢麦、主持、自由麦等模式,及包括各个模式中的上麦者均可通过会议属性实现,当会议属性发生更改时,会广播给房间内所有人。


创建语聊房间

首先创建者通过 AppServer 创建并加入语聊房间,IM 聊天室。在房主通过 AppServer 创建并进入房间后,通过音视频提供的会议属性接口修改房间的会议属性,从而自定义一些房间的属性。

我们可以通过一张图,来了解创建语聊房间接口的调用逻辑:

img

上图中每步涉及到的 iOS/Android 接口如下,其中部分调用到了 AppServer 的接口,开发者需要自己实现 AppServer 功能。

步骤iOS APIAndroid API
1. 创建语聊房间AppServer APIAndroid与iOS调用接口相同
2. 创建conferenceAppServer API http://a1.easemob.com/{orgname}/{appname}/conferences POSTAndroid与iOS调用接口相同
3. 创建 chatroomAppServer API http://a1.easemob.com/{orgname}/{appname}/chatrooms POSTAndroid与iOS调用接口相同
4. 创建成功返回conference ID,chatroom IDAppServer APIAndroid与iOS调用接口相同
5. 加入 conferenceEMClient.sharedClient.conferenceManager joinConferenceWithConfId: password: completion:open in new windowEMClient.getInstance().conferenceManager().joinConference(conferenceId, password, callback);open in new window
6. 加入 chatroomEMClient.sharedClient.roomManager joinChatroom: completion:open in new windowEMClient.getInstance().chatroomManager().joinChatRoom(chatRoomId, callback);open in new window
7. 设置会议属性EMClient.sharedClient.conferenceManager setConferenceAttribute: value: completion:open in new windowEMClient.getInstance().conferenceManager().setConferenceAttribute(key, value, callback);open in new window

加入语聊房间

当房主创建语聊房间后,其他人通过 AppServer 看到有房间被创建,可以输入房间密码加入到房间中。当加入房间后,就会收到会议属性变更的通知,从而得到会议属性。

我们可以通过一张图,来了解观众进入语聊房间接口的调用逻辑:

img

上图中每步涉及到的 iOS/Android 接口如下,其中部分调用到了 AppServer 的接口,开发者需要自己实现 AppServer 功能。

步骤iOS APIAndroid API
1.获取语聊房间列表AppServer APIAndroid与iOS调用接口相同
2.加入 conferenceEMClient.sharedClient.conferenceManager joinConferenceWithConfId: password: completion:open in new windowEMClient.getInstance().conferenceManager().joinConference(conferenceId, password, callback);open in new window
3.加入 chatroomEMClient.sharedClient.roomManager joinChatroom: completion:open in new windowEMClient.getInstance().chatroomManager().joinChatRoom(chatRoomId, callback);open in new window
4.同步会议属性EMConferenceManagerDelegate#-conferenceAttributeUpdated:attributes:open in new windowEMConferenceListener#onAttributesUpdated(attributes);open in new window

上麦

已在语聊房间的观众通过 IMServer 发送 message 向房主发起上麦请求,房主同意后,通过 MediaServer 改变会议属性,将观众上麦成为主播,成为主播后就能说话进行推流。房间内其他的人都能收到推流通知并进行订阅。

我们可以通过一张图,来了解观众上麦接口的调用逻辑:

img

上图中每步涉及到的 iOS/Android 接口如下:

步骤iOS APIAndroid API
1.请求上麦EMClient.sharedClient.chatManager sendMessage: progress: completion:open in new windowEMClient.getInstance().chatManager().sendMessage(msg);open in new window
2.改变角色属性EMClient.sharedClient.conferenceManager changeMemberRoleWithConfId: memberNames: role: completion:open in new windowEMClient.getInstance().conferenceManager().grantRole(targetRole);open in new window
3.上麦成为主播EMConferenceManagerDelegate#-roleDidChanged:open in new windowEMConferenceListener#onRoleChanged(role);open in new window
4.推流EMClient.sharedClient.conferenceManager publishConference: streamParam: completion:open in new windowEMClient.getInstance().conferenceManager().publish(param,callback);open in new window
5.收到推流通知EMConferenceManagerDelegate#-streamDidUpdate: addStream:open in new windowEMConferenceListener#onStreamAdded(stream);open in new window
6.订阅EMClient.sharedClient.conferenceManager subscribeConference: streamId: remoteVideoView: completion:open in new windowEMClient.getInstance().conferenceManager().subscribe(stream,surface,callback);open in new window

下麦、销毁房间

当主播在麦上时,如果想要下麦,同样通过 IMServer 向房主发送 message 发起下麦请求,这里无需房主同意,默认直接下麦。若房主主动将主播下麦,则没有之前这步,房主直接通过 MediaServer 改变会议属性,将主播下麦成为观众,主播成为观众后就停止推流。房主调用 AppServer 销毁房间,进而销毁conference、chatroom。

我们可以通过一张图,来了解主播下麦、房主销毁语聊房间接口的调用逻辑:

img

上图中每步涉及到的 iOS/Android 接口如下,其中部分调用到了 AppServer 的接口,开发者需要自己实现 AppServer 功能

步骤iOS APIAndroid API
1.请求下麦EMClient.sharedClient.chatManager sendMessage: progress: completion:open in new windowEMClient.getInstance().chatManager().sendMessage(msg);open in new window
2.改变角色属性EMClient.sharedClient.conferenceManager changeMemberRoleWithConfId: memberNames: role: completion:open in new windowEMClient.getInstance().conferenceManager().grantRole(targetRole);open in new window
3.下麦成为观众EMConferenceManagerDelegate#-roleDidChanged:open in new windowEMConferenceListener#onRoleChanged(role);open in new window
4.停止推流EMClient.sharedClient.conferenceManager unpublishConference: streamId: completion:open in new windowEMClient.getInstance().conferenceManager().unpublish(publishId,callback);open in new window
5.销毁语聊房间AppServer APIAndroid与iOS调用接口相同
6.销毁conferenceAppServer API http://a1-hsb.easemob.com/{orgname}/{appname}/conferences/{confrId} DELETEAndroid与iOS调用接口相同
7.销毁chatroomAppServer API http://a1.easemob.com/{orgname}/{appname}/chatrooms/{groupid} DELETEAndroid与iOS调用接口相同

本地混音

本地混音是指将几种不同的声音在发送端混在一起。例如常见的K歌场景,就需要将人唱歌的声音和歌曲的背景音乐进行混音处理。所以,在实现了基本的连麦功能后,我们还需要增加背景音乐的混音、播放控制。

在这里,主播可以在自己的客户端上选择要播放的音乐,然后通过 SDK 的 startAudioMixing 接口在本地与主播语音混音后播放给连麦听众和普通听众。并且连麦语音与背景音乐播放互不干扰,帮助用户活跃房间内的气氛。在默认情况下,背景音乐是循环播放的。


多种连麦模式

在语音聊天室 Demo 中,提供了三种模式,自由麦模式、主持模式、抢麦模式(开发者还可以基于此扩展更多模式玩法)。这三种模式就是通过会议属性区分的,当用户进入房间后,就可以知道当前的房间属于哪种模式。

自由麦模式:主播用户可以自由打开和关闭发言,实现起来较为简单就不过多赘述。

这里主要介绍一下,主持模式和抢麦模式的实现逻辑: