Skip to content

maxim-top/floo-rtc-ios

Repository files navigation

蓝莺IM SDK,iOS本地库

蓝莺IM,是由美信拓扑团队研发的新一代即时通讯云服务,SDK设计简单集成方便,服务采用云原生技术和多云架构,私有云也可按月付费。

蓝莺IM RTC SDK,则是在蓝莺IM SDK的基础上,以IM作为信令通道,提供了实时音视频功能,可以帮助用户快速将实时音视频功能集成到App中。目前的版本提供一对一的视频通话和语音通话功能。

Scc Count Badge Scc Count Badge

介绍

整个SDK只需使用一个公开的类:RTCEngineManager,通过RTCEngineManager获取到BMXRTCEngine,进而完成RTC相关业务功能。其它相关的类还有BMXRTCEngineListener、BMXRTCService和BMXRTCServiceListener。

其中: BMXRTCEngine用于提供RTC相关业务功能,比如进入房间、退出房间、发布流、订阅流等; BMXRTCEngineListener用于接收RTC相关业务事件,比如发布流成功、退出房间成功等; BMXRTCService用于发送RTC基本类型的消息,有发起呼叫、接听呼叫、结束通话; BMXRTCServiceListener用于接收RTC基本类型的消息。如果您还有其它类型的自定义消息,可以通过floo-android提供的消息机制创建自定义消息,发送和接收。

开发

蓝莺 IM RTC SDK 目前实现了一对一的视频和语音通话功能。集成方式有两种:可以通过 CocoaPods 自动集成我们的 floo-rtc-ios,也可以通过手动下载 floo-rtc-ios.framework, 手动添加到项目中。

方式一:自动集成/CocoaPods

提示:如果未安装cocoapods,请参照 CocoaPods安装

  1. 在 Podfile 文件中加入 floo-rtc-ios :

    pod 'floo-rtc-ios'
    
  2. 执行安装 ,命令如下

    pod install
    

    提示:如果无法安装 SDK 最新版本,运行以下命令更新本地的 CocoaPods 仓库列表

    pod repo update
    

方式二:手动集成

下载 floo-rtc-ios.framework , 然后将文件引用到您的项目中。

添加WebRTC依赖

在 Podfile文件中加入

  pod 'GoogleWebRTC', '~> 1.1'

创建用户界面

//创建对方画面视图
#if defined(RTC_SUPPORTS_METAL)
            _remoteVideoView = [[RTCMTLVideoView alloc] initWithFrame:CGRectZero];
#else
            RTCEAGLVideoView *remoteView = [[RTCEAGLVideoView alloc] initWithFrame:CGRectZero];
            _remoteVideoView = remoteView;
#endif            
            [self addSubview:_remoteVideoView];
//创建本地画面视图
            _localVideoView = [[UIView alloc] initWithFrame:CGRectZero];
            [self addSubview:_localVideoView];

音视频通话业务逻辑

  1. 导入RTCEngineManager
    #import <floo-rtc-ios/RTCEngineManager.h>
  1. 添加事件监听

在类接口声明中添加协议:BMXRTCEngineProtocol:

@interface CallViewController () < BMXRTCEngineProtocol >

添加BMXRTCEngineProtocol事件监听:

    [[RTCEngineManager engineWithType:kMaxEngine] addDelegate:self];
  1. 加入房间
    //设置视频分辨率
    BMXVideoConfig *videoConfig = [[BMXVideoConfig alloc] init];
    [videoConfig setWidth:720];
    [videoConfig setHeight:1280];
    [[RTCEngineManager engineWithType:kMaxEngine] setVideoProfile:videoConfig];
    //设置用户ID、pin密码和房间ID
    BMXRoomAuth *auth = [[BMXRoomAuth alloc] init];
    [auth setMUserId:userId];
    [auth setMToken:pin]; //房间pin密码,建议随机生成高强度密码
    [auth setMRoomId:roomId]; //主叫方无须设置roomId,房间创建成功事件会返回系统分配的roomId;被叫方需要设置与主叫方一样的roomId
    [[RTCEngineManager engineWithType:kMaxEngine] joinRoomWithAuth:auth];
  1. 加入房间结果回调
- (void)onJoinRoomWithInfo:(NSString*)info roomId:(long long)roomId error:(BMXErrorCode)error{
    //保存房间ID
    _roomId = roomId;
    if (error == BMXErrorCode_NoError) {
        //发布本地音视频流
        [[RTCEngineManager engineWithType:kMaxEngine] publishWithType:BMXVideoMediaType_Camera hasVideo:_hasVideo hasAudio:YES];
        //主叫方开始发送呼叫的消息
        if (_isCaller) {
            [self sendCallMessage];
        }
    }
}
  1. 收到对方视频流
- (void)onSubscribeWithStream:(BMXStream*)stream info:(NSString*)info error:(BMXErrorCode)error{
    if (error != BMXErrorCode_NoError) {
        return;
    }
    BOOL hasVideo = [stream getMEnableVideo];
    if (hasVideo) {
        BMXVideoCanvas *canvas = [[BMXVideoCanvas alloc] init];
        [canvas setMUserId:[stream getMUserId]];
        //设置用于渲染对方视频画面的视图
        [canvas setMView:(void*)_videoCallView.remoteVideoView];
        //渲染对方视频画面
        [[RTCEngineManager engineWithType:kMaxEngine] startRemoteViewWithCanvas:canvas];
    }
}
  1. 挂断通话
- (void)hangupByMe:(BOOL)byMe{
    //主动挂断一方需要通知对方挂断
    if (byMe) {
        [self sendHangupMessage];
    }
    //离开房间
    [[RTCEngineManager engineWithType:kMaxEngine] leaveRoom];
    //移除监听
    [[RTCEngineManager engineWithType:kMaxEngine] removeDelegate:self];
}

使用rtcService实现音视频通话信令

  1. 添加事件监听

在类接口声明中添加协议:BMXRTCServiceProtocol:

@interface CallViewController () < BMXRTCEngineProtocol, BMXRTCServiceProtocol >

添加BMXChatServiceProtocol和BMXRTCServiceProtocol事件监听:

    [[RTCEngineManager engineWithType:kMaxEngine] addDelegate:self];
    [[[BMXClient sharedClient] rtcService] addDelegate:self];
  1. 发送呼叫消息
- (void)sendCallMessage{
    //封装呼叫消息config
    BMXMessageConfig *config = [BMXMessageConfig createMessageConfigWithMentionAll: NO];
    [config setRTCCallInfo:_hasVideo?BMXMessageConfig_RTCCallType_VideoCall:BMXMessageConfig_RTCCallType_AudioCall roomId:_roomId initiator:_myId roomType:BMXMessageConfig_RTCRoomType_Broadcast pin:_pin];
    _callId = config.getRTCCallId;

    BMXMessage *msg = [BMXMessage createRTCMessageWithFrom:_myId to:_peerId type:BMXMessage_MessageType_Single conversationId:_peerId content:@"new call"];
    msg.config = config;
    //设置消息扩展信息,离线时服务端会发送推送
    [msg setExtension:@"{\"rtc\":\"call\"}"];
    [[[BMXClient sharedClient] rtcService] sendRTCMessageWithMsg:msg completion:^(BMXError *aError) {
    }];
}
  1. 发送接听消息
- (void)sendPickupMessage{
    //封装接听消息config
    BMXMessageConfig *config = [BMXMessageConfig createMessageConfigWithMentionAll: NO];
    [config setRTCPickupInfo:_callId];
    BMXMessage *msg = [BMXMessage createRTCMessageWithFrom:_myId to:_peerId type:BMXMessage_MessageType_Single conversationId:_peerId content:@""];
    msg.config = config;
    [[[BMXClient sharedClient] rtcService] sendRTCMessageWithMsg:msg completion:^(BMXError *aError) {
    }];
    //发送消息已读回执,确认主叫端呼叫的那条消息
    [self ackMessageWithMessageId:_messageId];
}

- (void)ackMessageWithMessageId:(long long)messageId{
    BMXMessage *msg = [[[BMXClient sharedClient] chatService] getMessage:messageId];
    if (msg) {
        [[[BMXClient sharedClient] chatService] ackMessageWithMsg:msg];
    }
}

  1. 发送挂断消息
- (void)sendHangupMessage{
    //封装挂断消息config
    BMXMessageConfig *config = [BMXMessageConfig createMessageConfigWithMentionAll: NO];
    if (_callId) {
        [config setRTCHangupInfo:_callId];
        _callId = nil;
    }
    //设置消息内容,用于界面展示通话时长、已取消、已拒绝、未接听等
    NSTimeInterval duration = 0.0;
    NSString *content = @"canceled"; //Caller canceled
    if (!_isCaller) {
        content = @"rejected"; //Callee rejected
    }else{
        if (_ringTimes == 0) { //Callee not responding
            content = @"timeout";
        }
    }
    if (_pickupTimestamp > 1.0) {
        duration = [self getTimeStamp] - _pickupTimestamp;
    }
    if (duration > 1.0) {
        content = [NSString stringWithFormat:@"%.0f", duration];
    }
    BMXMessage *msg = [BMXMessage createRTCMessageWithFrom:_myId to:_peerId type:BMXMessage_MessageType_Single conversationId:_peerId content:content];
    msg.config = config;
    [[[BMXClient sharedClient] rtcService] sendRTCMessageWithMsg:msg completion:^(BMXError *aError) {
        //同步挂断消息,用于实时更新会话界面的通话历史记录
        NSNotification *noti = [NSNotification notificationWithName:@"call" object:self userInfo:@{@"event":@"hangup"}];
        //发送通知
        [[NSNotificationCenter defaultCenter]postNotification:noti];
    }];
}

在会话界面处理挂断消息:
- (void)receiveNoti:(NSNotification*)noti
{
    NSString *event = noti.userInfo[@"event"];
    if ([event isEqualToString:@"hangup"]) {
        [[[BMXClient sharedClient] chatService] retrieveHistoryMessagesWithConversation:self.conversation refMsgId:0 size:1 completion:^(BMXMessageList *messageList, BMXError *error) {
            //会话界面的通话历史记录
            //...
       }];
    }
}

  1. 挂断通话
- (void)hangupByMe:(BOOL)byMe{
    //主动挂断一方需要通知对方挂断
    if (byMe) {
        [self sendHangupMessage];
    }
    //离开房间
    [[RTCEngineManager engineWithType:kMaxEngine] leaveRoom];
    //移除监听
    [[RTCEngineManager engineWithType:kMaxEngine] removeDelegate:self];
    [[[BMXClient sharedClient] rtcService] removeDelegate:self];
}
  1. 被叫方处理接收到的呼叫消息
#pragma mark - BMXRTCServiceProtocol
- (void)onRTCCallMessageReceiveWithMsg:(BMXMessage*)message {
    //解析呼叫消息config字段
    long long roomId = message.config.getRTCRoomId;
    long long myId = [self.account.usedId longLongValue];
    long long peerId = message.config.getRTCInitiator;
    if (myId == peerId){
        return;
    }
    NSString *pin = message.config.getRTCPin;
    NSString *callId = message.config.getRTCCallId;
    BOOL hasVideo = message.config.getRTCCallType == 1;
    //打开呼叫界面
    //...
}
  1. 处理接收到的挂断消息
- (void)onRTCHangupMessageReceiveWithMsg:(BMXMessage*)msg {
    //离开房间并确认消息为已读
}
  1. 处理接收到的接听消息
- (void)onRTCPickupMessageReceiveWithMsg:(BMXMessage*)msg{
    //如果消息是我的其它终端发送的
    if ([msg.config.getRTCCallId isEqualToString: _callId] && msg.fromId == _myId) {
        //关闭呼叫界面并确认消息已读
    }
}

快速集成文档参考蓝莺快速集成指南iOS版, 详细文档可参考floo-ios reference

祝玩得开心😊