Skip to content

easemob/voiceroom_demo_ios

Repository files navigation

voiceroom_demo_ios

客户端实现

场景描述

本文介绍如何通过环信 IM SDK 和 Agora Audio SDK 在你的 iOS 项目里实现语聊房的主要功能。注意本demo需要结合服务端源码部署到用户自己服务器上使用 https://github.com/easemob/easemob-voiceroom

编译问题

遇到文件svga.pbobjc m文件中报错,找不到OSAtomicCompareAndSwapPtrBarrier函数。 解决方式 显示的在文件中声明此函数bool OSAtomicCompareAndSwapPtrBarrier( void *__oldValue, void *__newValue, void * volatile *__theValue ); 或者 导入 #import <libkern/OSAtomic.h>即可解决

技术原理

房间管理

语聊房 SDK 内部依赖环信 IM 聊天室(Chatroom)与 Agora Audio 的音频房间(RTC Channel)。

语聊房内用户角色说明如下:

角色 描述
房主 语聊房创建者,在 Demo 中占用 0 号麦位,不可修改。房主可以接收、发送音频流。
主播 进入语聊房后,通过上麦成为主播,可以接收、发送音频流。
观众 进入语聊房后,接收音频流。申请上麦或房主邀请上麦后,可以和主播实时互动。

以下为房间管理流程图。

房间管理.png

房间管理流程如下:

  1. 用户利用手机号和验证码登录环信 IM。
  2. 房主可创建语聊房,普通用户加入语聊房。
  3. 加入环信 IM 和 RTC 频道。
  4. 进入语聊房,检查是否成功加入环信 IM 和 RTC 频道。
    • 若成功加入,房主可以发送本地音频流和消息,观众可以发消息。
    • 若未成功加入,退出房间,返回房间列表页面。
  5. 退出房间。

房间相关操作如下表所示:

操作 描述
创建房间 房主通过 App Server 创建语聊房,创建成功后自动加入语聊房。房主自动上麦成为主播,更新房间内麦位信息。
加入语聊房前,调用 VoiceRoomIMManager.configIM 方法初始化环信 IM,调用 ASRTCKit.getSharedInstance 方法初始化 Agora Audio。
加入房间 用户可调用 joinRoom 方法加入语聊房。加入语聊房前,调用 VoiceRoomIMManager.loginIM 方法登录环信 IM,然后调用 VoiceRoomIMManager.joinChatRoomself.rtcKit.joinChannel 方法加入聊天室和 RTC 频道,成功后再加入语聊房。
离开房间 观众或主播可调用 leaveRoom() 方法离开语聊房。房主离开语聊房,语聊房对象自动销毁,其他成员自动离开语聊房。
发送音频流 观众或主播可调用 self.rtcKit.joinChannel 方法发送音频流。
发送消息 语聊房内的用户可调用 VoiceRoomIMManager.sendMessage 或者 VoiceRoomIMManager.sendCustomMessage 方法发送消息。观众也可以调用 VoiceRoomIMManager.sendGift 方法发送礼物消息。

麦位管理

以下为麦位管理流程图:

麦位管理.png

麦位相关操作如下所示:

操作 描述
邀请上麦 房主调用 inviteUserToMic RESTful API 邀请观众上麦。观众收到 receiveInviteSite 回调,选择是否同意上麦。
- 观众调用 agreeInvite RESTful API 同意上麦,成为主播,App Server 设置聊天室属性。同时,房间内所有用户会收到该观众连麦的回调 VoiceRoomIMDelegate.chatroomAttributesDidUpdate,并更新房间内麦位信息。
申请上麦 观众调用 requestSpeak 方法向房主申请上麦。房主收到 VoiceRoomIMManager.receiveApplySite 回调,选择同意或拒绝申请。
- 房主调用 agreeUserApply 方法同意上麦申请,申请者收到 VoiceRoomIMDelegate.chatroomAttributesDidUpdate 回调并调用 self.rtcKit.joinChannel 方法成为主播。同时,房间内所有用户会收到该观众连麦的回调 VoiceRoomIMDelegate.chatroomAttributesDidUpdate,并更新房间内麦位信息。
- 房主调用 refuseApply RESTful API 方法拒绝上麦申请。
下麦 1. 主动下麦: 主播可调用 leaveMic 方法下麦成为观众。房间内所有用户会收到该连麦主播的下麦信息并更新房间内麦位信息。
2. 被踢下麦:房主调用 kickOff RESTful API 对主播发起下麦指令。该连麦主播收到 VoiceRoomIMDelegate.chatroomAttributesDidUpdate 回调,然后下麦成为观众。房间内所有用户会收到该连麦主播的下麦信息并更新房间内麦位信息。
禁麦 房主调用 muteMic RESTful API 禁麦,不允许指定连麦主播发言。该连麦主播收到 VoiceRoomIMDelegate.chatroomAttributesDidUpdate 回调,房间内所有用户会收到该连麦主播的禁麦信息并更新房间内麦位信息。
解禁麦位 房主调用 unmuteMic RESTful API 解禁麦位,恢复连麦主播的发言权限。该连麦主播收到 VoiceRoomIMDelegate.chatroomAttributesDidUpdate 回调,房间内所有用户会收到该连麦主播的解禁信息并更新房间内麦位信息。
锁麦 房主调用 lockMic RESTful API 锁麦,不允许任何人上该麦位。锁麦时,若该麦位有主播连麦,该主播收到 VoiceRoomIMDelegate.chatroomAttributesDidUpdate 回调,被踢下来成为普通观众,房间内所有用户会收到锁麦信息并更新房间内麦位信息。
解锁麦位 房主调用 unlockMic RESTful API 解锁麦位,使指定麦位恢复空闲状态,观众可以在该麦位申请上麦。房间内所有用户会收到麦位解封信息并更新房间内麦位信息。
跳麦 主播可调用 changeMic 方法换麦,即从当前麦位切换到另一个空闲麦位。

发送单向消息流程图

发送单向消息流程图.png

邀请用户上麦的流程如下:

  1. 房主调用 RESTFul API 邀请用户上麦。
  2. App Server 收到邀请消息后,利用房主角色向用户发送该消息。
  3. 用户同意邀请后调用 RESTful API 上麦。
  4. App Server 设置聊天室属性通知房间全员刷新房间设置。

用户申请上麦的流程如下:

  1. 用户调用 RESTful 接口申请上麦。
  2. App Server 收到上麦申请消息后以用户角色向房主发送该消息。
  3. 房主收到上麦申请后调用 RESTful API 同意上麦。
  4. App Server 设置聊天室属性通知房间全员刷新房间设置。

发送礼物消息流程图

发送礼物消息流程图.png

发送礼物消息的流程如下:

  1. 用户 A 发送礼物消息到 App Server。
  2. App Server 统计礼物消息后对用户 A 返回响应。
  3. SDK 将礼物消息发送到语聊房。

前提条件

项目配置

产品 SDK 下载 集成文档
环信即时通讯 IM SDK 环信即时通讯 IM SDK 大于等于 3.9.8 发送、接收消息、聊天室属性KV
Agora Audio SDK 声网 RTM SDK 4.0.1 实现音频通话

基本 API 参考

下表提供环信 IM SDK 和 Agora Audio SDK 的基本 API 参考。

Server Api文档,静态HTML需下载后查看

Demo对照Server Api枚举实现

房间管理 API 如下表所示:

API 实现功能
VoiceRoomBusinessApi.fetchRoomInfo 获取指定语聊房的信息。
VoiceRoomBusinessApi.createRoom 创建房间。
VoiceRoomBusinessApi.deleteRoom 根据 ID 删除房间。
VoiceRoomBusinessApi.modifyRoomInfo 修改语聊房信息。
VoiceRoomBusinessApi.fetchRoomList 获取房间列表。
VoiceRoomBusinessApi.fetchRoomMembers 获取房间内的成员。
VoiceRoomBusinessApi.joinRoom 加入房间。
VoiceRoomBusinessApi.validatePassWord 校验密码。
VoiceRoomBusinessApi.leaveRoom 离开房间。
VoiceRoomBusinessApi.kickUser 踢出房间。

麦位管理 API 如下表所示:

API 实现功能
VoiceRoomBusinessApi.fetchMicsInfo 获取麦位信息。
VoiceRoomBusinessApi.fetchApplyMembers 获取上麦申请列表。
VoiceRoomBusinessApi.inviteUserToMic 邀请上麦。
VoiceRoomBusinessApi.agreeInvite 用户同意上麦邀请。
VoiceRoomBusinessApi.refuseInvite 用户拒绝上麦邀请。
VoiceRoomBusinessApi.submitApply 提交上麦申请。
VoiceRoomBusinessApi.cancelApply 撤销上麦申请。
VoiceRoomBusinessApi.refuseApply 拒绝上麦申请。
VoiceRoomBusinessApi.agreeApply 同意上麦申请。
VoiceRoomBusinessApi.closeMic 关麦。
VoiceRoomBusinessApi.cancelCloseMic 开麦。
VoiceRoomBusinessApi.leaveMic 主动下麦。
VoiceRoomBusinessApi.muteMic 封禁指定麦位。
VoiceRoomBusinessApi.unmuteMic 解禁指定麦位。
VoiceRoomBusinessApi.exchangeMic 换麦。
VoiceRoomBusinessApi.kickMic 踢用户下麦。
VoiceRoomBusinessApi.lockMic 锁定麦位。
VoiceRoomBusinessApi.unlockMic 解锁麦位。

礼物榜单 API 如下表所示:

API 实现功能
VoiceRoomBusinessApi.fetchGiftContribute 获取赠送礼物榜单。
VoiceRoomBusinessApi.giftTo 赠送礼物。

VoiceRoomIMManager.swift(对HyphenateChat IMSDK进行封装) API 如下表所示:

API 实现功能
VoiceRoomIMManager.configIM 初始化IM。
VoiceRoomIMManager.loginIM 登录IM。
VoiceRoomIMManager.addChatRoomListener 添加IM消息以及聊天室回调监听。
VoiceRoomIMManager.removeListener 移除IM消息以及聊天室回调监听。

Agora_audio iOS sdk api封装回调

API 实现功能
AgoraRtcEngineKit.sharedEngine(withAppId: AgoraConfig.rtcId, delegate: nil) 初始化RTC。
ASRTCKit.joinVoicRoomWith 加入RTC channel。
ASRTCKit.setClientRole 设置RTC角色。
ASRTCKit.leaveChannel 离开RTC channel。

初始设置

加入语聊房前,进行环信 IM SDK 初始化Agora Audio 初始化设置。

加入/离开环信 IM 聊天室或者声网 RTC 频道

API 实现功能
joinChatroom 加入语聊房。房间内的观众会收到 userDidJoinChatroom 回调。用户加入语聊房后才能接收或发布音频流。
leaveChatroom 离开语聊房。其他成员收到 userDidLeaveChatroom 回调。房主离开语聊房后,房间对象自动销毁,其他成员会自动离开语聊房。
joinChannelbyToken 加入 RTC 频道。用户加入语聊房后才能接收或发布音频流。房间内的观众会收到 ASManagerDelegate.didRtcLocalUserJoinedOfUid 回调
leaveChannel 离开 RTC 频道。

1.加入和离开 RTC 频道的链接是否正确?

通过 App Server 加入或离开语聊房的方法的示例代码如下:

// 加入语聊房
    func uploadStatus( status: Bool) {
        guard let roomId = self.roomInfo?.room?.room_id  else { return }
        VoiceRoomBusinessRequest.shared.sendPOSTRequest(api: .joinRoom(roomId: roomId), params: [:]) { dic, error in
            if let result = dic?["result"] as? Bool,error == nil,result {
                self.view.makeToast("Joined successful!".localized(),point: self.toastPoint, title: nil, image: nil, completion: nil)
            } else {
                self.didHeaderAction(with: .back,destroyed: false)
            }
        }
    }
// 离开语聊房
    @objc private func leaveRoom() {
        if let room_id = roomInfo?.room?.room_id {
            VoiceRoomBusinessRequest.shared.sendDELETERequest(api: .leaveRoom(roomId: room_id), params: [:]) { map, err in
                print(map?["result"] as? Bool ?? false)
            }
        }
    }

环信 IM 相关回调以及处理请在 VoiceRoomViewController+IM 文件中查看相关方法。

送礼物及其底部时间回调请在 VoiceRoomViewController+ChatBar 文件中查看相关方法。

麦位相关

请在 VoiceRoomViewController+Mic 文件查看相关方法。

音频相关

配置声网音频sdk初始化AppId AgoraRtcEngineKit.sharedEngine(withAppId: AgoraConfig.rtcId, delegate: nil)

主播调用以下方法设置音频流:

API 实现功能
[setAudioProfile [2/2\]](https://docs.agora.io/cn/voice-call-4.x/API Reference/ios_ng/API/class_irtcengine.html#api_setaudioprofile2) 设置音频编码属性。
[muteLocalAudioStream](https://docs.agora.io/cn/voice-call-4.x/API Reference/ios_ng/API/class_irtcengine.html#api_mutelocalaudiostream) 主播可以关闭或开启本地麦克风。
[adjustRecordingSignalVolume](https://docs.agora.io/cn/voice-call-4.x/API Reference/ios_ng/API/class_irtcengine.html#api_adjustrecordingsignalvolume) 调节人声音量。

附加功能

最佳音效

调用setAudioEffectPreset

    rtcKit.setChannelProfile(.liveBroadcasting)
    rtcKit.setAudioProfile(.musicHighQuality)
    rtcKit.setAudioScenario(.gameStreaming)

AI降噪

调用 [enableInEarMonitoring [2/2\]](https://docs.agora.io/cn/voice-call-4.x/API Reference/ios_ng/API/class_irtcengine.html#api_enableinearmonitoring2) 方法开启主播的AI降噪功能。

/*
* 开启/关闭 AI降噪
* @param
* Qreturn 开启/关闭回声消除的结果
*/
public func setAINS(with level: AINS_STATE) {
        switch level {
        case .high:
        rtcKit.setParameters("{\"che.audio.ains_mode\":2}")
        rtcKit.setParameters("{\"che.audio.nsng.lowerBound\":10}")
        rtcKit.setParameters("{\"che.audio.nsng.lowerMask\":10}")
        rtcKit.setParameters("{\"che.audio.nsng.statisticalbound\":0}")
        rtcKit.setParameters("{\"che.audio.nsng.finallowermask\":8}")
        rtcKit.setParameters("{\"che.audio.nsng.enhfactorstastical\":200}")
        case .mid:
        rtcKit.setParameters("{\"che.audio.ains_mode\":2}")
        rtcKit.setParameters("{\"che.audio.nsng.lowerBound\":80}")
        rtcKit.setParameters("{\"che.audio.nsng.lowerMask\":50}")
        rtcKit.setParameters("{\"che.audio.nsng.statisticalbound\":5}")
        rtcKit.setParameters("{\"che.audio.nsng.finallowermask\":30}")
        rtcKit.setParameters("{\"che.audio.nsng.enhfactorstastical\":200}")
        case .off:
        rtcKit.setParameters("{\"che.audio.ains_mode\":0}")
        rtcKit.setParameters("{\"che.audio.nsng.lowerBound\":80}")
        rtcKit.setParameters("{\"che.audio.nsng.lowerMask\":50}")
        rtcKit.setParameters("{\"che.audio.nsng.statisticalbound\":5}")
        rtcKit.setParameters("{\"che.audio.nsng.finallowermask\":30}")
        rtcKit.setParameters("{\"che.audio.nsng.enhfactorstastical\":200}")
    }
}

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages