|
|
|
# iOS推流SDK开发者使用说明文档
|
|
|
|
|
|
|
|
[TOC]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 1 版本信息
|
|
|
|
|
|
|
|
- 版本: 2.6.0
|
|
|
|
- 日期: 2023年04月19日
|
|
|
|
|
|
|
|
## 2 推流SDK简介及加载流程
|
|
|
|
|
|
|
|
功能特性:
|
|
|
|
|
|
|
|
| 功能特性 | 描述 |
|
|
|
|
| -------------- | ---------------------------------- |
|
|
|
|
| 前后摄像头切换 | 支持手机前后摄像头切换直播; |
|
|
|
|
| 自定义码率 | 支持调整直播视频码率; |
|
|
|
|
| 自定义分辨率 | 支持设置直播画面分辨率; |
|
|
|
|
| 横竖屏 | 支持手机横屏或竖屏模式直播; |
|
|
|
|
| 音量设置 | 支持调整麦克风采集音量大小; |
|
|
|
|
| 帧率设置 | 支持设置直播帧率; |
|
|
|
|
| 闪光灯开关 | 支持开启闪光灯; |
|
|
|
|
| 美颜 | 支持磨皮、美白、粉嫩三种美颜特效; |
|
|
|
|
| 水印 | 支持设置图片水印; |
|
|
|
|
| 聊天 | 支持主播与观众互动聊天; |
|
|
|
|
| 获取在线人数 | 支持获取直播间在线人数 |
|
|
|
|
| 支持https协议 | 支持接口https请求 |
|
|
|
|
| 直播带货 | 直播带货 |
|
|
|
|
|
|
|
|
### 2.1 SDK目的
|
|
|
|
|
|
|
|
```
|
|
|
|
CC云直播iOS推流SDK不仅为 iOS 开发者提供了丰富、快捷的云直播接口还提供了美颜滤镜等功能,帮助开发者在iOS平台上快速与云直播对接实现手机推流直播。使用苹果手机推流
|
|
|
|
```
|
|
|
|
|
|
|
|
### 2.2 IDE版本要求
|
|
|
|
|
|
|
|
```
|
|
|
|
使用Xcode10.0版本及以上版本均可
|
|
|
|
```
|
|
|
|
|
|
|
|
### 2.3 SDK适用范围
|
|
|
|
|
|
|
|
```
|
|
|
|
因SDK中编码方式使用的是硬编码,硬编码是在iOS9.0以后才开放的,所以本SDK只适用于iOS9.0及以上版本,无法支持iOS8.x版本的系统
|
|
|
|
```
|
|
|
|
|
|
|
|
### 2.4 真机 or 模拟器
|
|
|
|
|
|
|
|
```
|
|
|
|
本SDK在真机状态下能正常推流,在模拟器状态下不能正常推流.
|
|
|
|
```
|
|
|
|
|
|
|
|
### 2.5 Info.plist配置要求
|
|
|
|
|
|
|
|
```
|
|
|
|
App Transport Security Settings
|
|
|
|
Privacy - Camera Usage Description
|
|
|
|
Privacy - Location When In Use Usage Description
|
|
|
|
Privacy - Microphone Usage Description
|
|
|
|
Privacy - Photo Library Usage Description
|
|
|
|
```
|
|
|
|
|
|
|
|
### 2.6 工程配置基本要求
|
|
|
|
|
|
|
|
```
|
|
|
|
1. Build Phases -> Link Binary With Librarires 添加一下HDLiveKit.framework这个SDK
|
|
|
|
2. General -> Frameworks,Libraries 将HDLiveKit.framework 选择Embed & Sign
|
|
|
|
```
|
|
|
|
|
|
|
|
### 2.7 配置对象类PushParameters
|
|
|
|
|
|
|
|
```
|
|
|
|
@property(nonatomic, copy)NSString *userId;//用户ID
|
|
|
|
@property(nonatomic, copy)NSString *roomId;//直播间号
|
|
|
|
@property(nonatomic, copy)NSString *viewerName;//用户名称
|
|
|
|
@property(nonatomic, copy)NSString *token;//密码
|
|
|
|
@property(nonatomic, assign)BOOL security;//是否使用https,YES:https NO:http(建议开启)
|
|
|
|
```
|
|
|
|
|
|
|
|
## 3 网络请求类及代理介绍
|
|
|
|
|
|
|
|
### CCPushUtil:推流工具类,单例类
|
|
|
|
|
|
|
|
### CCPushUtilDelegate:对应的代理
|
|
|
|
|
|
|
|
### 3.1.1 登录
|
|
|
|
|
|
|
|
```
|
|
|
|
/**
|
|
|
|
* @brief 服务器请求初始化
|
|
|
|
* @param parameters 登陆参数
|
|
|
|
* @return request 实例对象
|
|
|
|
* @return parameters.userId 必要参数
|
|
|
|
* @return parameters.roomId 必要参数
|
|
|
|
* @return parameters.viewerName 必要参数
|
|
|
|
* @return parameters.token 必要参数
|
|
|
|
* @return parameters.security 必要参数
|
|
|
|
*/
|
|
|
|
- (void)loginWithParameters:(PushParameters *)parameters;
|
|
|
|
```
|
|
|
|
|
|
|
|
### 3.1.2登录对应的代理方法
|
|
|
|
|
|
|
|
```
|
|
|
|
/**
|
|
|
|
* @brief 登录请求成功
|
|
|
|
*/
|
|
|
|
-(void)requestLoginSucceedWithViewerId:(NSString *)viewerId;
|
|
|
|
/**
|
|
|
|
* @brief 登录请求失败
|
|
|
|
*/
|
|
|
|
-(void)requestLoginFailed:(NSError *)error reason:(NSString *)reason;
|
|
|
|
```
|
|
|
|
|
|
|
|
### 3.1.3 登陆成功以后到退出登陆以前可能会有用户自定义消息的代理方法被触发(定制功能,无定制需求请忽略此代理方法)
|
|
|
|
|
|
|
|
```
|
|
|
|
/*
|
|
|
|
* @brief 用户自定义消息
|
|
|
|
*/
|
|
|
|
- (void)customMessage:(NSString *)message;
|
|
|
|
/**
|
|
|
|
* @brief dict 房间信息
|
|
|
|
* manuallyRecordMode //是否开启手动录制 0 未开启 1 开启
|
|
|
|
* module 房间模板类型
|
|
|
|
*/
|
|
|
|
-(void)roomInfo:(NSDictionary *)dict;
|
|
|
|
```
|
|
|
|
|
|
|
|
### 3.1.4 获取房间推流配置成功
|
|
|
|
|
|
|
|
```
|
|
|
|
/**
|
|
|
|
* @brief 获取房间推流配置成功
|
|
|
|
*/
|
|
|
|
-(void)requestLiveConfigSuccess:(NSDictionary *)info;
|
|
|
|
```
|
|
|
|
|
|
|
|
### 3.1.5 获取房间推流配置失败
|
|
|
|
|
|
|
|
```
|
|
|
|
/**
|
|
|
|
* @brief 获取房间推流配置失败
|
|
|
|
*/
|
|
|
|
-(void)requestLiveConfigFail:(NSString *)message;
|
|
|
|
```
|
|
|
|
|
|
|
|
### 3.1.6 收到强制下播消息
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
/**
|
|
|
|
* @brief 强制下播
|
|
|
|
*/
|
|
|
|
- (void)streamBeTerminated:(NSString *)message;
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 3.2推流过程中会回调的代理有
|
|
|
|
|
|
|
|
```
|
|
|
|
/**
|
|
|
|
* @brief 推流失败
|
|
|
|
*/
|
|
|
|
-(void)pushFailed:(NSError *)error reason:(NSString *)reason;
|
|
|
|
/**
|
|
|
|
* @brief 正在连接网络,注:可以进行一些UI的操作
|
|
|
|
*/
|
|
|
|
- (void) isConnectionNetWork;
|
|
|
|
/**
|
|
|
|
* @brief 连接网络完成
|
|
|
|
*/
|
|
|
|
- (void) connectedNetWorkFinished;
|
|
|
|
/**
|
|
|
|
* @brief 设置连接状态
|
|
|
|
* status含义 1:正在连接,3:已连接(表示推流成功),5:未连接(表示推流失败)
|
|
|
|
*/
|
|
|
|
- (void) setConnectionStatus:(NSInteger)status;
|
|
|
|
/**
|
|
|
|
* @brief 点击开始推流按钮,获取liveid
|
|
|
|
*/
|
|
|
|
- (void) getLiveidBeforPush:(NSString *)liveid;
|
|
|
|
```
|
|
|
|
|
|
|
|
### 3.3 推流前的接口以及设置
|
|
|
|
|
|
|
|
```
|
|
|
|
/**
|
|
|
|
* @brief 得到房间可用的最大码率,注:在登录接口后,才能取到
|
|
|
|
*/
|
|
|
|
- (NSInteger)getMaxBitrate;
|
|
|
|
/**
|
|
|
|
* @brief 设置预览页面
|
|
|
|
* @param previewView
|
|
|
|
*/
|
|
|
|
- (void)setPreview:(UIView*)previewView;
|
|
|
|
/**
|
|
|
|
* @brief 开始推流,注:设置好码率,分辨率,帧率,和预览页面后才可以开始推流
|
|
|
|
* @param cameraFront是否是前置摄像头推流
|
|
|
|
*/
|
|
|
|
- (void)startPushWithCameraFront;
|
|
|
|
/**
|
|
|
|
* @brief 设置分辨率videoSize,(重要:分辨率长宽一定要设置为偶数,否则推出来的视频会有绿边)建议不要设置太离谱,码率iBitRate,100到本房间可用的最大码率之间设置,
|
|
|
|
* 如果小于100,码率会设置成最小值100,如果码率大于最大码率,码率会设置成最大值,帧率iFrameRate建议设置20到30之间,
|
|
|
|
* 小于20或大于30会设置成默认值25
|
|
|
|
*/
|
|
|
|
- (void)setVideoSize:(CGSize)videoSize BitRate:(int)iBitRate FrameRate:(int)iFrameRate;
|
|
|
|
/**
|
|
|
|
* @brief 设置预览页面
|
|
|
|
* @param previewView表示预览页面,重新创建一个UIView对象,作为预览页面,
|
|
|
|
* 不要在previewView表示预览页面上面添加其他控件,也不要使用UIView的
|
|
|
|
* 子类当作参数传进去
|
|
|
|
*/
|
|
|
|
- (void)setPreview:(UIView*)previewView;
|
|
|
|
```
|
|
|
|
|
|
|
|
### 3.4 推流中的接口以及设置
|
|
|
|
|
|
|
|
#### 3.4.1 停止推流
|
|
|
|
|
|
|
|
```
|
|
|
|
/**
|
|
|
|
* @brief 停止推流
|
|
|
|
*/
|
|
|
|
- (void)stopPush;
|
|
|
|
```
|
|
|
|
|
|
|
|
#### 3.4.2 停止推流的代理方法
|
|
|
|
|
|
|
|
```
|
|
|
|
/*
|
|
|
|
* @brief 停止推流成功
|
|
|
|
*/
|
|
|
|
- (void)stopPushSuccessful;
|
|
|
|
```
|
|
|
|
|
|
|
|
#### 3.4.3 其它
|
|
|
|
|
|
|
|
```
|
|
|
|
/**
|
|
|
|
* @brief 设置前后置摄像头
|
|
|
|
*/
|
|
|
|
- (void)setCameraFront:(Boolean)bCameraFrontFlag;
|
|
|
|
/**
|
|
|
|
* @brief 开启闪光灯
|
|
|
|
*/
|
|
|
|
- (void)setTorch:(BOOL)torchOn;
|
|
|
|
/**
|
|
|
|
* @brief 设置声音大小,0-10,0和10分别表示静音和最大音量
|
|
|
|
*/
|
|
|
|
- (void)setMicGain:(float)micGain;
|
|
|
|
/**
|
|
|
|
* @brief 设置美颜滤镜
|
|
|
|
* @param smooth 磨皮系数 取值范围[0.0, 1.0]
|
|
|
|
* @param white 美白系数 取值范围[0.0, 1.0]
|
|
|
|
* @param pink 粉嫩系数 取值范围[0.0, 1.0]
|
|
|
|
*/
|
|
|
|
- (void)setCameraBeautyFilterWithSmooth:(float)smooth white:(float)white pink:(float)pink;
|
|
|
|
/**
|
|
|
|
* @brief 设置水印(整个可设置的宽高和设置的屏幕分辨率,在切换摄像头之后需要在调用一次)
|
|
|
|
* @param image 水印图片(去除水印的时候只需要赋值nil,再次调用该接口)
|
|
|
|
* @param rect 坐标 取值范围(设置的分辨率的宽高)
|
|
|
|
*/
|
|
|
|
- (void)addWaterMask:(UIImage *)image rect:(CGRect)rect;
|
|
|
|
/**
|
|
|
|
* @brief 停止预览
|
|
|
|
*/
|
|
|
|
- (void)stopPreview;
|
|
|
|
```
|
|
|
|
|
|
|
|
### 3.5 没有推流时可以请求的接口以及设置(此接口和推流无关)
|
|
|
|
|
|
|
|
```
|
|
|
|
/**
|
|
|
|
* @brief 退出登录
|
|
|
|
*/
|
|
|
|
- (void)logout;
|
|
|
|
/**
|
|
|
|
* @brief 单例并设置代理
|
|
|
|
*/
|
|
|
|
+ (instancetype)sharedInstanceWithDelegate:(id)delegate;
|
|
|
|
```
|
|
|
|
|
|
|
|
### 3.6 手动录制
|
|
|
|
|
|
|
|
```
|
|
|
|
/*
|
|
|
|
@brief 开始录制
|
|
|
|
返回值
|
|
|
|
success 成功/失败;
|
|
|
|
dict = {
|
|
|
|
result = OK
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
- (void)startRecordWithCompletion:(void(^)(BOOL success, NSDictionary *dict))completion;
|
|
|
|
/*
|
|
|
|
@brief 暂停录制
|
|
|
|
*/
|
|
|
|
- (void)pauseRecordWithCompletion:(void(^)(BOOL success, NSDictionary *dict))completion;
|
|
|
|
/*
|
|
|
|
@brief 继续录制
|
|
|
|
*/
|
|
|
|
- (void)resumeRecordWithCompletion:(void(^)(BOOL success, NSDictionary *dict))completion;
|
|
|
|
/*
|
|
|
|
@brief 停止录制,停止录制后想要继续录制需要调用开始录制方法
|
|
|
|
*/
|
|
|
|
- (void)stopRecordWithCompletion:(void(^)(BOOL success, NSDictionary *dict))completion;
|
|
|
|
```
|
|
|
|
|
|
|
|
### 3.7 聊天的代理(如果不对接聊天功能,请忽略)
|
|
|
|
|
|
|
|
```
|
|
|
|
/**
|
|
|
|
* @brief 收到私聊信息
|
|
|
|
*/
|
|
|
|
- (void)on_private_chat:(NSString *)str;
|
|
|
|
/**
|
|
|
|
* @brief 收到公聊信息
|
|
|
|
*/
|
|
|
|
- (void)on_chat_message:(NSString *)str;
|
|
|
|
```
|
|
|
|
|
|
|
|
### 3.8 获取房间人数以及房间信息的代理方法
|
|
|
|
|
|
|
|
```
|
|
|
|
/**
|
|
|
|
* @brief 获取当前在线人数
|
|
|
|
* 调用- (void)roomUserCount;方法会触发此代理
|
|
|
|
*/
|
|
|
|
- (void)room_user_count:(NSString *)str;
|
|
|
|
/**
|
|
|
|
* @brief 获取房间用户列表
|
|
|
|
* 调用- (void)roomContext;方法会触发此代理
|
|
|
|
*/
|
|
|
|
- (void)receivePublisherId:(NSString *)str onlineUsers:(NSMutableDictionary *)dict;
|
|
|
|
```
|
|
|
|
|
|
|
|
### 3.9 聊天调用方法(如果不对接聊天功能,请忽略)
|
|
|
|
|
|
|
|
```
|
|
|
|
/**
|
|
|
|
* @brief 发送公聊信息
|
|
|
|
*/
|
|
|
|
- (void)chatMessage:(NSString *)message ;
|
|
|
|
/**
|
|
|
|
* @brief 发送私聊信息
|
|
|
|
*/
|
|
|
|
- (void)privateChatWithTouserid:(NSString *)touserid msg:(NSString *)msg;
|
|
|
|
```
|
|
|
|
|
|
|
|
### 3.10 获取房间人数以及房间信息
|
|
|
|
|
|
|
|
```
|
|
|
|
/**
|
|
|
|
* @brief 询问房间信息,同上面接口相似的是,此接口一定要在登录成功后才可以调用,登录不成功或者退出登录后不能调用此接口,因为此房间信息中包含用户列表信息,所以可以采用定时器循环调用的方法来调用,也可以在有用户,黑名单,白名单信息变动的时候调用,在SDK里面和此信息紧紧相关联的是聊天信息,如果有用户变动,没有及时调用此接口的话,那在调用SDK聊天系统的时候,可能会因为取不到发消息的用户的信息而产生崩溃,如果不使用推流SDK的聊天系统的话,可以忽略此接口
|
|
|
|
此方法对应代理:- (void)receivePublisherId:(NSString *)str onlineUsers:(NSMutableDictionary *)dict;
|
|
|
|
*/
|
|
|
|
- (void)roomContext;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief 获取在线房间人数,当登录成功后即可调用此接口,推不推流都能够调用,并且都会有返回值,登录不成功或者退出登录后就不可以调用了,如果要求实时性比较强的话,可以写一个定时器,不断调用此接口,几秒中发一次就可以,然后在代理回调函数中,处理返回的数据
|
|
|
|
此方法对应代理:- (void)room_user_count:(NSString *)str;
|
|
|
|
*/
|
|
|
|
- (void)roomUserCount;
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 3.11 房间互动功能配置信息(代理方法)
|
|
|
|
|
|
|
|
| 方法 | 注释 | 所在类文件 |
|
|
|
|
| ----------------------------- | ------------ | ---------------------- |
|
|
|
|
| (void)onInteractionConfigure: | 互动功能配置 | HDLiveKit/CCPushUtil.h |
|
|
|
|
|
|
|
|
示例代码
|
|
|
|
|
|
|
|
```objc
|
|
|
|
/// 房间互动配置
|
|
|
|
/// @param model 配置项
|
|
|
|
- (void)onInteractionConfigure:(HDSInteractionConfigureModel *)model;
|
|
|
|
```
|
|
|
|
|
|
|
|
#### HDSInteractionConfigureModel
|
|
|
|
|
|
|
|
| 参数 | 类型 | 注释 | 所在类文件 |
|
|
|
|
| ----------------- | ----------------------- | -------------------------- | -------------------------- |
|
|
|
|
| isLiveStoreSwitch | BOOL | 直播带货开关 0:关闭 1:开启 | HDLiveKit/PushParameters.h |
|
|
|
|
| giftModel | HDSInteractionGiftModel | 打赏 | HDLiveKit/PushParameters.h |
|
|
|
|
|
|
|
|
##### HDSInteractionGiftModel
|
|
|
|
|
|
|
|
| 参数 | 类型 | 注释 | 所在类文件 |
|
|
|
|
| ------------------ | ------- | ----------------------------------------------- | -------------------------- |
|
|
|
|
| giftFunctionConfig | Integer | 打赏礼物功能配置 0:关闭 1:直播间配置 2:全局配置 | HDLiveKit/PushParameters.h |
|
|
|
|
| specialEffects | Integer | 打赏礼物特效配置 0:关闭 1:左侧特效 2:全局特效 | HDLiveKit/PushParameters.h |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 3.12 获取互动组件Token(主动方法)
|
|
|
|
|
|
|
|
| 方法 | 注释 | 所在类文件 |
|
|
|
|
| --------------------------------- | ------------------ | ---------------------- |
|
|
|
|
| (void)getInteractionToken: token: | 获取互动组件 token | HDLiveKit/CCPushUtil.h |
|
|
|
|
|
|
|
|
示例代码
|
|
|
|
|
|
|
|
```objc
|
|
|
|
/// 获取互动token
|
|
|
|
/// @param closure 操作回调
|
|
|
|
/// @param token interactionTokenBlock token回调 "completeHandler回调中 result == YES ,返回token ,result == NO时返回@""(空字符串) "
|
|
|
|
- (void)getInteractionToken:(completeHandler)closure token:(interactionTokenBlock)token;
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### 3.13 退出登录(主动方法)
|
|
|
|
|
|
|
|
| 方法 | 注释 | 所在类文件 |
|
|
|
|
| ------------ | ---------------------------- | ---------------------- |
|
|
|
|
| (void)logout | 退出登录(退出房间必须调用) | HDLiveKit/CCPushUtil.h |
|
|
|
|
|
|
|
|
示例代码
|
|
|
|
|
|
|
|
```objc
|
|
|
|
- (void)logout;
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 4错误码及错误描述
|
|
|
|
|
|
|
|
### 以下错误都会在封装在返回的错误中的(NSError *)error中,为自定义的错误,另外reason:(NSString *)reason会是服务器返回的错误信息
|
|
|
|
|
|
|
|
### 4.1 错误类型定义如下
|
|
|
|
|
|
|
|
```
|
|
|
|
typedef NS_ENUM(NSInteger, ERROR_SERVICE_TYPE) {
|
|
|
|
ERROR_PASSWORD = 1001,//@"密码错误"
|
|
|
|
ERROR_HEART_BEAT = 1002,//@"心跳请求失败"
|
|
|
|
ERROR_LONG_TIME_NOPUSH = 1003,//@"长时间未推流"
|
|
|
|
ERROR_RTMP_LINK = 1004,//@"RTMP连接失败"
|
|
|
|
ERROR_RTMP_TIMEOUT = 1005,//@"RTMP连接超时"
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef NS_ENUM(NSInteger, ERROR_SYSTEM_TYPE) {
|
|
|
|
ERROR_RETURNDATA = 1006,//@"返回内容格式错误"
|
|
|
|
ERROR_PARAMETER = 1007,//@"可能是参数错误"
|
|
|
|
ERROR_NETWORK = 1008,//@"网络异常"
|
|
|
|
ERROR_NETWORK_TIMEOUT = 1009,//@"网络超时"
|
|
|
|
ERROR_ROOM_TYPE = 1010,//@"暂不支持多主讲"
|
|
|
|
};
|
|
|
|
```
|
|
|
|
|
|
|
|
### 4.2 错误类型分类
|
|
|
|
|
|
|
|
#### 4.2.1 业务错误
|
|
|
|
|
|
|
|
```
|
|
|
|
1. 密码错误
|
|
|
|
2. 心跳请求失败
|
|
|
|
3. 长时间未推流
|
|
|
|
4. RTMP连接失败
|
|
|
|
5. RTMP连接超时
|
|
|
|
```
|
|
|
|
|
|
|
|
#### 4.2.2 系统错误
|
|
|
|
|
|
|
|
```
|
|
|
|
1. 返回内容格式错误
|
|
|
|
2. 可能是参数错误
|
|
|
|
3. 网络异常
|
|
|
|
4. 网络超时
|
|
|
|
5. 暂不支持多主讲
|
|
|
|
```
|
|
|
|
|
|
|
|
## 5直播流程说明
|
|
|
|
|
|
|
|
### 5.1 登录
|
|
|
|
|
|
|
|
### 5.2 设置码率,分辨率,帧率,预览页面,前后置摄像头
|
|
|
|
|
|
|
|
### 5.3 开始推流(设置声音,闪光灯),设置推流中屏幕不会锁屏。
|
|
|
|
|
|
|
|
### 5.4 停止推流
|
|
|
|
|
|
|
|
### 5.5 退出登录
|
|
|
|
|
|
|
|
### 5.6 音频输入源类型有 普通耳机,蓝牙耳机,麦克风
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#创盛视联数码科技(北京)有限公司 |