语音房开发, 这里使用的是声网和网易云信
声网提供连麦的功能,
网易云信处理消息的同步
1, 待验证
1.1 加入房间
注册好网易云信,再去注册声网的服务
let request = NIMChatroomEnterRequest()
//
NIMSDK.shared().chatroomManager.enterChatroom(request) { error, chatRoomModel, member in
self.configAgoraRtc()
}
public func configAgoraRtc(){
let config = AgoraRtcEngineConfig()
//
agorat = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self)
agorat.enableAudioVolumeIndication(400, smooth: 3, report_vad:true)
agorat.adjustPlaybackSignalVolume(2)
agorat.setChannelProfile(.liveBroadcasting)
agorat.enableDeepLearningDenoise(true)
agorat.setClientRole(.audience)
}
调整为
let request = NIMChatroomEnterRequest()
//
NIMSDK.shared().chatroomManager.enterChatroom(request) { error, chatRoomModel, member in
}
self.configAgoraRtc()
因为,如果没网,就一起 gg 了
1.2 消息同步, 性能优化,耗电方向的角度
语音房,按职能( 权限 )的角度,一般可分为,游客和管理员
语音房,1 / 3 左右的功能,不对游客开发
所以, 房间的成员信息变更的时候,不用通知游客
游客的手机,减少了很多网络 socket 传输,减少耗电
1.2.1 网易云信的消息,一般用 P2P,和 Chatroom,
这里可使用 Team , 群组功能
成为管理员,就加入了房间对应的群组,接收关联的消息
1.3, 刚开始开发,按照一切非常顺利
公司发现啥问题,马上补
KPI 非,用户授予
可能性,那么多。进度,能不赶
1.4 常见的优化 ( 请求加速 )手段,略
加流程大法,好
弱网环境下,点击上麦,
用户头像,马上上去了,
调用声网修改角色的方法,gg
2, 功能
发消息的常见流程:
有一个基于时间的考量
用户点击,发消息,UI 上,秒发出
UI, 就是障眼法
200 ms 后,这个网络请求 pending
消息的旁边出现一个进度条
后来,请求超时了,
列表的该消息,旁边出现,
一个重试按钮,和提示语 ( 请检查网络 )
2.1 公屏消息
可以移动端,直接发消息
let session = NIMSession(chatK, type: NIMSessionType.chatroom)
let message = NIMMessage()
let object = NIMCustomObject()
object.attachment = HelloMessage()
// 构造出具体消息并注入附件
message.messageObject = object
do {
try NIMSDK.shared().chatManager.send(message, to: session)
} catch let err {
print(err)
}
消息编码
class HelloMessage: NSObject, NIMCustomAttachment{
var txt = ""
func encode() -> String {
let dict: [String: Any] = ["txt": txt,
"type": 6]
var content = ""
do {
let data = try JSONSerialization.data(withJSONObject: dict, options: [])
if let val = String(data: data, encoding: .utf8){
content = val
}
} catch {
print(error)
}
return content
}
注册解码
NIMCustomObject.registerCustomDecoder(TheDecoder())
解码器
class TheDecoder: NSObject, NIMCustomAttachmentCoding {
/// 消息解码 处理
func decodeAttachment(_ content: String?) -> NIMCustomAttachment? {
var attachment: NIMCustomAttachment?
guard let contentData = content?.data(using: .utf8),
let dic = try? JSONSerialization.jsonObject(with: contentData, options: .mutableContainers) as? [String:Any]
else{ return nil }
guard let type = dic["type"] as? Int
else {
return nil
}
switch type{
case 6:
// 见后面的 3.1
if let model = RoomTxtModel.deserialize(from: dic){
attachment = HelloMessage.instance(model)
}
default:
()
}
return attachment
}
}
收到消息的 NIMSDK 的回调方法
func onRecvMessages(_ messages: [NIMMessage]) {
if let object = message.messageObject as? NIMCustomObject{
if let tmpModel = object.attachment as? HelloMessage{
var item = tmpModel.item
item.id = message.messageId
// 见 3.2
subject.onNext([item])
}
}
}
2.1.1 公屏消息, 的另一种实现
用户发消息,调用后端 API.
后端调用网易云信的接口,
然后房间内所有的用户收到消息,同步公屏的内容
2.2, 上麦
本地判断成功, 秒上
用户自己的手机上, 他的头像覆盖麦位,
开声网的角色
同时,调用 API ,上传自己的麦位信息,
等待服务端云信,下方的消息,
是否有异常,需要在该麦位旁边,来一把叉
3, 三方库
3.1, HandyJSON
Swift 项目中,数据 ( 模型 ) 一般使用结构体,
NIMSDK 的附件 attachment, id 类型, 一般继承自 NSObject
需要来一个转换
class HelloMessage: NSObject, NIMCustomAttachment, JSONy{
required override init() { }
class func instance(_ model: RoomTxtModel) -> HelloMessage{
if let tmp = model.toJSON(), let data = HelloMessage.deserialize(from: tmp){
return data
}
else{
return RoomTxtModel()
}
}
var item: RoomTxtModel{
if let tmp = toJSON(), let data = RoomTxtModel.deserialize(from: tmp){
return data
}
else{
return RoomTxtModel()
}
}
}
3.2 RxDataSources
var subject = PublishSubject<[RoomTxtModel]>()
公屏就是一个 tableView,
RoomTxtModel 对应 cell,
每一个 RoomTxtModel 的 id, 就是云信消息的 id
( 区别开,拿来就用 )