支持业务层直接推送视频帧,支持屏幕共享推流
This commit is contained in:
parent
14431c1570
commit
b85cee5d0d
Binary file not shown.
|
|
@ -12,6 +12,7 @@
|
||||||
#import "UIView+SellyCloud.h"
|
#import "UIView+SellyCloud.h"
|
||||||
#import "SLSVideoGridView.h"
|
#import "SLSVideoGridView.h"
|
||||||
#import "TokenGenerator.h"
|
#import "TokenGenerator.h"
|
||||||
|
#import <ReplayKit/ReplayKit.h> //屏幕采集
|
||||||
|
|
||||||
@interface SellyVideoCallConferenceController ()<SellyRTCSessionDelegate>
|
@interface SellyVideoCallConferenceController ()<SellyRTCSessionDelegate>
|
||||||
|
|
||||||
|
|
@ -23,7 +24,7 @@
|
||||||
|
|
||||||
@property (weak, nonatomic) IBOutlet SLSVideoGridView *grid;
|
@property (weak, nonatomic) IBOutlet SLSVideoGridView *grid;
|
||||||
@property (weak, nonatomic) IBOutlet UILabel *duration;
|
@property (weak, nonatomic) IBOutlet UILabel *duration;
|
||||||
|
@property (nonatomic, strong)RPSystemBroadcastPickerView *systemBroadcastPicker;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation SellyVideoCallConferenceController
|
@implementation SellyVideoCallConferenceController
|
||||||
|
|
@ -60,6 +61,29 @@
|
||||||
//显示本地view
|
//显示本地view
|
||||||
[self attachLocalStream];
|
[self attachLocalStream];
|
||||||
self.localAudioEnable = true;
|
self.localAudioEnable = true;
|
||||||
|
|
||||||
|
[self addBroadcastButton];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)addBroadcastButton {
|
||||||
|
if (@available(iOS 12.0, *)) {
|
||||||
|
self.systemBroadcastPicker = [[RPSystemBroadcastPickerView alloc]
|
||||||
|
initWithFrame:CGRectMake(UIScreen.mainScreen.bounds.size.width-80, UIScreen.mainScreen.bounds.size.height-180, 60, 60)];
|
||||||
|
|
||||||
|
NSString *bundleId = [NSBundle mainBundle].bundleIdentifier;
|
||||||
|
self.systemBroadcastPicker.preferredExtension = [NSString stringWithFormat:@"%@.ScreenShareUploader",bundleId];// 你的 extension bundle id
|
||||||
|
self.systemBroadcastPicker.showsMicrophoneButton = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)startScreenCapture:(id)sender {
|
||||||
|
for (UIView *view in self.systemBroadcastPicker.subviews) {
|
||||||
|
if ([view isKindOfClass:[UIButton class]]) {
|
||||||
|
[((UIButton *)view) sendActionsForControlEvents:(UIControlEventAllEvents)];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewDidDisappear:(BOOL)animated {
|
- (void)viewDidDisappear:(BOOL)animated {
|
||||||
|
|
@ -187,6 +211,17 @@
|
||||||
[session renewToken:newToken];
|
[session renewToken:newToken];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)rtcSession:(SellyRTCSession *)session onScreenShareStatusChanged:(SellyScreenShareState)state {
|
||||||
|
if (state == SellyScreenShareStateStarted) {
|
||||||
|
self.localVideoEnable = false;
|
||||||
|
[self.session startScreenCapture];
|
||||||
|
}
|
||||||
|
else if (state == SellyScreenShareStateStopped) {
|
||||||
|
self.localVideoEnable = true;
|
||||||
|
[self.session enableLocalVideo:true];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (SellyRTCSession *)session {
|
- (SellyRTCSession *)session {
|
||||||
if (!_session) {
|
if (!_session) {
|
||||||
_session = [[SellyRTCSession alloc] initWithType:false];
|
_session = [[SellyRTCSession alloc] initWithType:false];
|
||||||
|
|
|
||||||
314
README.md
314
README.md
|
|
@ -1,42 +1,42 @@
|
||||||
# SellyCloudSDK
|
# SellyRTC iOS SDK 接入文档
|
||||||
|
|
||||||
# 📘 SellyRTC iOS SDK 接入文档
|
本文档介绍如何使用 **SellyRTCSession** 快速集成一对一或多人音视频通话功能,包括:
|
||||||
|
|
||||||
本文档介绍如何使用 **SellyRTCSession** 快速集成一对一或多人音视频通话功能,包括基本接入、音视频控制、数据处理、事件回调、统计与 Token 更新机制。
|
- Session 创建与基础通话流程
|
||||||
|
- 本地 / 远端画面渲染
|
||||||
|
- 音视频控制与通话路由
|
||||||
|
- 屏幕分享与外部视频源推流
|
||||||
|
- 自定义消息、统计与 Token 机制
|
||||||
|
- 连接状态与事件回调
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📑 目录
|
## 📑 目录
|
||||||
1. [准备工作](#准备工作)
|
|
||||||
|
1. [准备工作](#准备工作)
|
||||||
2. [快速开始](#快速开始)
|
2. [快速开始](#快速开始)
|
||||||
- 创建 Session
|
|
||||||
- 设置本地/远端画面
|
|
||||||
- 配置视频参数
|
|
||||||
- 加入频道
|
|
||||||
- 结束通话
|
|
||||||
3. [常用功能](#常用功能)
|
3. [常用功能](#常用功能)
|
||||||
- 开关音视频
|
4. [屏幕分享与外部视频源](#屏幕分享与外部视频源)
|
||||||
- 切换摄像头
|
5. [视频帧前后处理](#视频帧前后处理)
|
||||||
- 静音远端
|
6. [事件回调(Delegate)](#事件回调delegate)
|
||||||
- 音频输出控制
|
7. [通话统计](#通话统计)
|
||||||
- 发送自定义消息
|
8. [Token 过期机制](#token-过期机制)
|
||||||
- Token 更新
|
9. [连接状态说明](#连接状态说明)
|
||||||
4. [视频/音频帧处理](#视频音频帧处理)
|
10. [常见问题](#常见问题)
|
||||||
5. [事件回调 (Delegate)](#事件回调-delegate)
|
|
||||||
6. [通话统计](#通话统计)
|
|
||||||
7. [Token 过期机制](#token-过期机制)
|
|
||||||
8. [常见问题](#常见问题)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# 🔧 准备工作
|
# 🔧 准备工作
|
||||||
|
|
||||||
确保已正确集成 `SellyRTC.framework` 并导入头文件:
|
1. 集成 SellyRTC.framework
|
||||||
|
2. 引入头文件:
|
||||||
|
|
||||||
```objc
|
```objc
|
||||||
#import <SellyRTC/SellyRTC.h>
|
#import <SellyRTC/SellyRTC.h>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
3. 在真机运行(摄像头/麦克风需要硬件支持)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# 🚀 快速开始
|
# 🚀 快速开始
|
||||||
|
|
@ -44,39 +44,34 @@
|
||||||
## 1. 创建 Session
|
## 1. 创建 Session
|
||||||
|
|
||||||
```objc
|
```objc
|
||||||
// YES = 单聊(P2P) NO = 多人会议
|
/// @param isP2p YES 表示一对一通话(P2P 直连),NO 表示多人通话(房间 / 会议模式)
|
||||||
|
///
|
||||||
|
/// P2P 模式(YES):
|
||||||
|
/// - 点对点直连,端到端延迟更低
|
||||||
|
/// - 适合普通一对一音视频通话
|
||||||
self.session = [[SellyRTCSession alloc] initWithType:YES];
|
self.session = [[SellyRTCSession alloc] initWithType:YES];
|
||||||
self.session.delegate = self;
|
self.session.delegate = self;
|
||||||
```
|
```
|
||||||
|
|
||||||
⚠️ `init` 和 `new` 已禁用,必须使用 `initWithType:`。
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2. 设置本地 & 远端画布
|
## 2. 设置本地和远端画布
|
||||||
|
|
||||||
```objc
|
```objc
|
||||||
// 本地视频
|
|
||||||
SellyRtcVideoCanvas *local = [SellyRtcVideoCanvas new];
|
SellyRtcVideoCanvas *local = [SellyRtcVideoCanvas new];
|
||||||
local.view = self.localView;
|
local.view = self.localView;
|
||||||
[self.session setLocalCanvas:local];
|
[self.session setLocalCanvas:local];
|
||||||
|
|
||||||
// 远端视频(多人时 userId 必填)
|
|
||||||
SellyRtcVideoCanvas *remote = [SellyRtcVideoCanvas new];
|
SellyRtcVideoCanvas *remote = [SellyRtcVideoCanvas new];
|
||||||
remote.view = self.remoteView;
|
remote.view = self.remoteView;
|
||||||
remote.userId = @"remoteUser";
|
remote.userId = @"remoteUserId";
|
||||||
[self.session setRemoteCanvas:remote];
|
[self.session setRemoteCanvas:remote];
|
||||||
```
|
```
|
||||||
|
|
||||||
> 多人会议:可多次调用 `setRemoteCanvas:`。
|
|
||||||
> SDK 根据 `canvas.userId` 将对应远端视频渲染到指定 view。
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3. 配置视频参数(可选)
|
## 3. 配置视频参数(可选)
|
||||||
|
|
||||||
必须在加入频道前配置:
|
|
||||||
|
|
||||||
```objc
|
```objc
|
||||||
SellyRTCVideoConfiguration *config = [SellyRTCVideoConfiguration defaultConfig];
|
SellyRTCVideoConfiguration *config = [SellyRTCVideoConfiguration defaultConfig];
|
||||||
config.width = 720;
|
config.width = 720;
|
||||||
|
|
@ -88,15 +83,29 @@ self.session.videoConfig = config;
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4. 加入频道 / 发起通话
|
## 4. 打开本地预览
|
||||||
|
|
||||||
```objc
|
```objc
|
||||||
[self.session startWithChannelId:@"room123" token:@"xxxx-token"];
|
[self.session startPreview];
|
||||||
|
```
|
||||||
|
|
||||||
|
关闭:
|
||||||
|
|
||||||
|
```objc
|
||||||
|
[self.session stopPreview];
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5. 结束通话
|
## 5. 加入频道(开始通话)
|
||||||
|
|
||||||
|
```objc
|
||||||
|
[self.session startWithChannelId:@"room_123" token:@"your-token"];
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 结束通话
|
||||||
|
|
||||||
```objc
|
```objc
|
||||||
[self.session end];
|
[self.session end];
|
||||||
|
|
@ -106,48 +115,42 @@ self.session.videoConfig = config;
|
||||||
|
|
||||||
# 🎛 常用功能
|
# 🎛 常用功能
|
||||||
|
|
||||||
## 开/关本地视频
|
## 开关本地视频
|
||||||
|
|
||||||
```objc
|
```objc
|
||||||
[self.session enableLocalVideo:NO];
|
|
||||||
[self.session enableLocalVideo:YES];
|
[self.session enableLocalVideo:YES];
|
||||||
|
[self.session enableLocalVideo:NO];
|
||||||
```
|
```
|
||||||
|
|
||||||
## 开/关本地音频采集
|
## 开关本地音频
|
||||||
|
|
||||||
```objc
|
```objc
|
||||||
[self.session enableLocalAudio:NO];
|
[self.session enableLocalAudio:NO];
|
||||||
[self.session enableLocalAudio:YES];
|
[self.session enableLocalAudio:YES];
|
||||||
```
|
```
|
||||||
|
|
||||||
## 切换前后摄像头
|
## 切换摄像头
|
||||||
|
|
||||||
```objc
|
```objc
|
||||||
[self.session switchCamera];
|
[self.session switchCamera];
|
||||||
```
|
```
|
||||||
|
|
||||||
## 静音远端音频
|
## 静音远端
|
||||||
|
|
||||||
```objc
|
```objc
|
||||||
// P2P 模式 userId 可传 nil
|
[self.session muteRemoteAudioStream:@"remoteUser" mute:YES];
|
||||||
[self.session muteRemoteAudioStream:nil mute:YES];
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 控制音频输出(扬声器/听筒)
|
## 音频输出(听筒/扬声器)
|
||||||
|
|
||||||
```objc
|
```objc
|
||||||
[self.session setAudioOutput:AVAudioSessionPortOverrideSpeaker];
|
[self.session setAudioOutput:AVAudioSessionPortOverrideSpeaker];
|
||||||
```
|
```
|
||||||
|
|
||||||
如有耳机 / 蓝牙设备,建议外部使用 `AVRoutePickerView`。
|
|
||||||
|
|
||||||
## 发送自定义消息
|
## 发送自定义消息
|
||||||
|
|
||||||
```objc
|
```objc
|
||||||
[self.session sendMessage:@"Hello World"
|
[self.session sendMessage:@"hello" completion:^(NSError *error) {}];
|
||||||
completion:^(NSError *error) {
|
|
||||||
if (error) NSLog(@"发送失败: %@", error);
|
|
||||||
}];
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 更新 Token
|
## 更新 Token
|
||||||
|
|
@ -158,203 +161,154 @@ self.session.videoConfig = config;
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# 🎥 视频 / 音频帧处理
|
# 🖥 屏幕分享与外部视频源
|
||||||
|
|
||||||
## 视频采集前处理(美颜、滤镜、自定义 GPU)
|
## 开启屏幕分享
|
||||||
|
|
||||||
```objc
|
```objc
|
||||||
- (CVPixelBufferRef)rtcSession:(SellyRTCSession *)session
|
[self.session startScreenCapture];
|
||||||
onCaptureVideoFrame:(CVPixelBufferRef)pixelBuffer {
|
```
|
||||||
|
|
||||||
// 1. 执行美颜、贴纸、旋转等处理
|
屏幕分享状态回调:
|
||||||
// 2. 返回处理后的 pixelBuffer
|
|
||||||
|
|
||||||
|
```objc
|
||||||
|
- (void)rtcSession:(SellyRTCSession *)session onScreenShareStatusChanged:(SellyScreenShareState)state {}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 外部推流(自定义采集)
|
||||||
|
|
||||||
|
```objc
|
||||||
|
[self.session enableLocalVideo:YES];
|
||||||
|
[self.session pushExternalVideoFrame:pixelBuffer];
|
||||||
|
```
|
||||||
|
|
||||||
|
常用于游戏画面/ReplayKit 输出/第三方渲染等。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 🎥 视频帧前后处理
|
||||||
|
|
||||||
|
## 本地采集前处理(美颜/滤镜等)
|
||||||
|
|
||||||
|
```objc
|
||||||
|
- (CVPixelBufferRef)rtcSession:(SellyRTCSession *)session onCaptureVideoFrame:(CVPixelBufferRef)pixelBuffer {
|
||||||
return pixelBuffer;
|
return pixelBuffer;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## 远端视频解码后回调(AI 分析、自定义渲染)
|
## 远端渲染前处理(做 AI/贴纸/录像)
|
||||||
|
|
||||||
```objc
|
```objc
|
||||||
- (BOOL)rtcSession:(SellyRTCSession *)session
|
- (BOOL)rtcSession:(SellyRTCSession *)session onRenderVideoFrame:(SellyRTCVideoFrame *)videoFrame userId:(NSString *)userId {
|
||||||
onRenderVideoFrame:(SellyRTCVideoFrame *)videoFrame
|
|
||||||
userId:(NSString *)userId {
|
|
||||||
|
|
||||||
// 返回 YES:继续渲染
|
|
||||||
// 返回 NO:丢弃该帧
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# 📡 事件回调 (Delegate)
|
# 📡 事件回调(Delegate)
|
||||||
|
|
||||||
|
## 通话严重错误
|
||||||
|
|
||||||
```objc
|
```objc
|
||||||
#pragma mark - SellyRTCSessionDelegate
|
- (void)rtcSession:(SellyRTCSession *)session onError:(NSError *)error {}
|
||||||
```
|
```
|
||||||
|
|
||||||
## 通话错误(不可恢复)
|
## 远端音视频开关
|
||||||
|
|
||||||
```objc
|
```objc
|
||||||
- (void)rtcSession:(SellyRTCSession *)session onError:(NSError *)error;
|
- (void)rtcSession:(SellyRTCSession *)s videoEnabled:(BOOL)enabled userId:(NSString *)userId {}
|
||||||
```
|
```
|
||||||
|
|
||||||
## 远端启用/关闭音视频
|
## 自定义消息
|
||||||
|
|
||||||
```objc
|
```objc
|
||||||
- (void)rtcSession:(SellyRTCSession *)session
|
- (void)rtcSession:(SellyRTCSession *)s didReceiveMessage:(NSString *)msg userId:(NSString *)uid {}
|
||||||
videoEnabled:(BOOL)enabled
|
|
||||||
userId:(NSString *)userId;
|
|
||||||
|
|
||||||
- (void)rtcSession:(SellyRTCSession *)session
|
|
||||||
audioEnabled:(BOOL)enabled
|
|
||||||
userId:(NSString *)userId;
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 收到消息
|
## 流级连接状态
|
||||||
|
|
||||||
```objc
|
```objc
|
||||||
- (void)rtcSession:(SellyRTCSession *)session
|
- (void)rtcSession:(SellyRTCSession *)s connectionStateChanged:(SellyRTCConnectState)state userId:(NSString *)uid {}
|
||||||
didReceiveMessage:(NSString *)message
|
|
||||||
userId:(NSString *)userId;
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 连接状态变化
|
## 会话级连接状态
|
||||||
|
|
||||||
```objc
|
```objc
|
||||||
- (void)rtcSession:(SellyRTCSession *)session
|
- (void)rtcSession:(SellyRTCSession *)s onRoomConnectionStateChanged:(SellyRoomConnectionState)state {}
|
||||||
connectionStateChanged:(SellyRTCConnectState)state
|
|
||||||
userId:(NSString *)userId;
|
|
||||||
```
|
|
||||||
|
|
||||||
连接状态包括:
|
|
||||||
|
|
||||||
```
|
|
||||||
Disconnected
|
|
||||||
Connecting
|
|
||||||
Connected
|
|
||||||
Reconnecting
|
|
||||||
Failed
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 用户加入/离开
|
## 用户加入/离开
|
||||||
|
|
||||||
```objc
|
```objc
|
||||||
- (void)rtcSession:(SellyRTCSession *)session onUserJoined:(NSString *)userId;
|
- (void)rtcSession:(SellyRTCSession *)s onUserJoined:(NSString *)uid {}
|
||||||
|
- (void)rtcSession:(SellyRTCSession *)s onUserLeave:(NSString *)uid {}
|
||||||
- (void)rtcSession:(SellyRTCSession *)session onUserLeave:(NSString *)userId;
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 通话时长
|
## 通话时长
|
||||||
|
|
||||||
```objc
|
```objc
|
||||||
- (void)rtcSession:(SellyRTCSession *)session onDuration:(NSInteger)duration;
|
- (void)rtcSession:(SellyRTCSession *)s onDuration:(NSInteger)duration {}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Token 回调
|
||||||
|
|
||||||
|
```objc
|
||||||
|
- (void)rtcSession:(SellyRTCSession *)s tokenWillExpire:(NSString *)token {}
|
||||||
|
- (void)rtcSession:(SellyRTCSession *)s tokenExpired:(NSString *)token {}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 屏幕分享状态
|
||||||
|
|
||||||
|
```objc
|
||||||
|
- (void)rtcSession:(SellyRTCSession *)s onScreenShareStatusChanged:(SellyScreenShareState)state {}
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# 📊 通话统计信息
|
# 📊 通话统计
|
||||||
|
|
||||||
```objc
|
```objc
|
||||||
- (void)rtcSession:(SellyRTCSession *)session
|
- (void)rtcSession:(SellyRTCSession *)s onStats:(SellyRTCP2pStats *)stats userId:(NSString *)uid {}
|
||||||
onStats:(SellyRTCP2pStats *)stats
|
|
||||||
userId:(NSString *)userId;
|
|
||||||
```
|
```
|
||||||
|
|
||||||
可获取:
|
|
||||||
|
|
||||||
- 上下行码率
|
|
||||||
- 帧率
|
|
||||||
- 丢包率
|
|
||||||
- RTT
|
|
||||||
- 解码帧数等
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# 🔑 Token 过期机制
|
# 🔑 Token 过期机制
|
||||||
|
|
||||||
## Token 即将过期
|
- Token 将在 **60 秒前** 触发 `tokenWillExpire`
|
||||||
|
- Token 过期后通话继续,但重连会失败
|
||||||
```objc
|
- 请及时调用 `renewToken:`
|
||||||
- (void)rtcSession:(SellyRTCSession *)session tokenWillExpire:(NSString *)token;
|
|
||||||
```
|
|
||||||
|
|
||||||
业务应立即向服务器请求新 Token:
|
|
||||||
|
|
||||||
```objc
|
|
||||||
[self.session renewToken:newToken];
|
|
||||||
```
|
|
||||||
|
|
||||||
## Token 已过期(通话仍继续)
|
|
||||||
|
|
||||||
```objc
|
|
||||||
- (void)rtcSession:(SellyRTCSession *)session tokenExpired:(NSString *)token;
|
|
||||||
```
|
|
||||||
|
|
||||||
⚠️ 过期后通话不受影响,但**断网重连会失败**,务必及时更新 Token。
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# ❓ 常见问题
|
# 🌐 连接状态说明
|
||||||
|
|
||||||
### Q1:多人远端画面如何渲染?
|
`connectionState` 可读取当前房间状态:
|
||||||
|
|
||||||
重复调用:
|
- Disconnected
|
||||||
|
- Connecting
|
||||||
```objc
|
- Connected
|
||||||
SellyRtcVideoCanvas *canvas = [SellyRtcVideoCanvas new];
|
- Reconnecting
|
||||||
canvas.view = remoteViewX;
|
|
||||||
canvas.userId = @"userX";
|
|
||||||
|
|
||||||
[self.session setRemoteCanvas:canvas];
|
|
||||||
```
|
|
||||||
|
|
||||||
SDK 会根据 `userId` 做路由。
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Q2:远端画面不显示?
|
# ❓ 常见问题 FAQ
|
||||||
|
|
||||||
|
### Q:远端画面不显示怎么办?
|
||||||
|
|
||||||
检查:
|
检查:
|
||||||
|
|
||||||
- remoteCanvas.view 是否正确添加
|
1. 是否设置了正确的 `remoteCanvas.userId`
|
||||||
- remoteCanvas.userId 是否一致
|
2. 是否 addSubview 到界面
|
||||||
- 是否重复 addSubview 覆盖
|
3. 是否在 onUserJoined 后调用 setRemoteCanvas
|
||||||
- 是否调用了 `setRemoteCanvas:`
|
|
||||||
|
### Q:如何实现摄像头与屏幕分享切换?
|
||||||
|
|
||||||
|
1. 开启摄像头 → enableLocalVideo:YES
|
||||||
|
2. 开启屏幕分享 → startScreenCapture
|
||||||
|
3. 收到屏幕分享结束 → 恢复摄像头
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Q3:如何做画中画 (PiP)?
|
|
||||||
|
|
||||||
将本地 + 远端视频放入一个 containerView:
|
|
||||||
|
|
||||||
```text
|
|
||||||
[container addSubview:remoteView]
|
|
||||||
[container addSubview:localView] // 小窗
|
|
||||||
```
|
|
||||||
|
|
||||||
并使用:
|
|
||||||
|
|
||||||
```objc
|
|
||||||
AVPictureInPictureControllerContentSource *source =
|
|
||||||
[[AVPictureInPictureControllerContentSource alloc] initWithActiveVideoCallSource:sampleBufferLayer
|
|
||||||
contentView:container];
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# 🎉 完成
|
|
||||||
|
|
||||||
您已完成 SellyRTC 的全部集成内容。
|
|
||||||
如需更多帮助,可继续咨询:""
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Author
|
|
||||||
|
|
||||||
Caleb, liaoqiang1123@gmail.com
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
SellyCloudSDK is available under the MIT license. See the LICENSE file for more info.
|
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -19,6 +19,7 @@
|
||||||
#import "SellyRTCSession.h"
|
#import "SellyRTCSession.h"
|
||||||
#import "SellyRTCVideoConfiguration.h"
|
#import "SellyRTCVideoConfiguration.h"
|
||||||
#import "SellyRTCSessionDelegate.h"
|
#import "SellyRTCSessionDelegate.h"
|
||||||
|
#import "SellyRTCReplayKitHandler.h"
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#if 0
|
#if 0
|
||||||
#elif defined(__arm64__) && __arm64__
|
#elif defined(__arm64__) && __arm64__
|
||||||
// Generated by Apple Swift version 6.2 effective-5.10 (swiftlang-6.2.0.19.9 clang-1700.3.19.1)
|
// Generated by Apple Swift version 6.2.1 effective-5.10 (swiftlang-6.2.1.4.8 clang-1700.4.4.1)
|
||||||
#ifndef SELLYCLOUDSDK_SWIFT_H
|
#ifndef SELLYCLOUDSDK_SWIFT_H
|
||||||
#define SELLYCLOUDSDK_SWIFT_H
|
#define SELLYCLOUDSDK_SWIFT_H
|
||||||
#pragma clang diagnostic push
|
#pragma clang diagnostic push
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
#import "SellyPusherManagerDelegate.h"
|
#import "SellyPusherManagerDelegate.h"
|
||||||
#import "SellyRTCEngine.h"
|
#import "SellyRTCEngine.h"
|
||||||
#import "SellyRTCP2pStats.h"
|
#import "SellyRTCP2pStats.h"
|
||||||
|
#import "SellyRTCReplayKitHandler.h"
|
||||||
#import "SellyRTCSession.h"
|
#import "SellyRTCSession.h"
|
||||||
#import "SellyRTCSessionDelegate.h"
|
#import "SellyRTCSessionDelegate.h"
|
||||||
#import "SellyRtcVideoCanvas.h"
|
#import "SellyRtcVideoCanvas.h"
|
||||||
|
|
|
||||||
|
|
@ -61,4 +61,11 @@ typedef NS_ENUM(NSInteger, SellyRoomConnectionState) {
|
||||||
SellyRoomStateFailed,
|
SellyRoomStateFailed,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//屏幕分享状态
|
||||||
|
typedef NS_ENUM(uint8_t, SellyScreenShareState) {
|
||||||
|
SellyScreenShareStateStarted = 1, // 开始
|
||||||
|
SellyScreenShareStatePaused = 2, // 暂停
|
||||||
|
SellyScreenShareStateResumed = 3, // 恢复
|
||||||
|
SellyScreenShareStateStopped = 4, // 结束
|
||||||
|
};
|
||||||
#endif /* SellyPublicDefinition_h */
|
#endif /* SellyPublicDefinition_h */
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
//
|
||||||
|
// SellyRTCReplayKitHandler.h
|
||||||
|
// SellyCloudSDK
|
||||||
|
//
|
||||||
|
// Created by Caleb on 12/10/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <ReplayKit/ReplayKit.h>
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface SellyRTCReplayKitHandler : RPBroadcastSampleHandler
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
|
|
@ -79,6 +79,12 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
//更新token
|
//更新token
|
||||||
- (void)renewToken:(NSString * _Nonnull)token;
|
- (void)renewToken:(NSString * _Nonnull)token;
|
||||||
|
|
||||||
|
//Starts screen sharing.
|
||||||
|
- (void)startScreenCapture;
|
||||||
|
|
||||||
|
//外部推流,不使用sdk默认的视频采集
|
||||||
|
- (void)pushExternalVideoFrame:(CVPixelBufferRef)pixelBuffer;
|
||||||
|
|
||||||
//
|
//
|
||||||
@property (nonatomic, weak)id<SellyRTCSessionDelegate> delegate;
|
@property (nonatomic, weak)id<SellyRTCSessionDelegate> delegate;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
#import "SellyRTCP2pStats.h"
|
#import "SellyRTCP2pStats.h"
|
||||||
#import "SellyRTCVideoFrame.h"
|
#import "SellyRTCVideoFrame.h"
|
||||||
|
|
||||||
@class SellyRTCSession;
|
@class SellyRTCSession;
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_BEGIN
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
@ -113,6 +114,11 @@ token过期后依然可以正常通话,但是断网重连会失败
|
||||||
*/
|
*/
|
||||||
- (void)rtcSession:(SellyRTCSession * _Nonnull)session tokenExpired:(NSString *)token;
|
- (void)rtcSession:(SellyRTCSession * _Nonnull)session tokenExpired:(NSString *)token;
|
||||||
|
|
||||||
|
/**
|
||||||
|
屏幕分享状态发生变化
|
||||||
|
*/
|
||||||
|
- (void)rtcSession:(SellyRTCSession * _Nonnull)session onScreenShareStatusChanged:(SellyScreenShareState)state;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
NS_ASSUME_NONNULL_END
|
NS_ASSUME_NONNULL_END
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue