Commit 0502f728b80d4818f0d1c5bd341330baf83019d5

Authored by 朱林
1 parent 197ebef1

no message

Showing 48 changed files with 2328 additions and 646 deletions
CNLivePlayerSDKTest/CNLiveMsgTools.framework/CNLiveMsgTools 0 → 100755
No preview for this file type
CNLivePlayerSDKTest/CNLiveMsgTools.framework/Emoji.plist 0 → 100644
No preview for this file type
CNLivePlayerSDKTest/CNLiveMsgTools.framework/Headers/CNLiveMsgManager.h 0 → 100644
  1 +//
  2 +// CNLiveMsgManager.h
  3 +// CNLiveMsgTools
  4 +//
  5 +// Created by cnliveJunBo on 17/2/23.
  6 +// Copyright © 2017年 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import <Foundation/Foundation.h>
  10 +
  11 +@interface CNLiveMsgManager : NSObject
  12 +
  13 +
  14 ++ (NSString *)getVersion;
  15 +
  16 +
  17 ++ (instancetype)sharedCNLiveMsgManager;
  18 +
  19 +
  20 +- (void)setToolsInfoWithInfoId:(NSString *)infoId
  21 + infoName:(NSString *)infoName
  22 + infoUrl:(NSString *)infoUrl;
  23 +
  24 +
  25 +- (NSDictionary *)getToolsInfo;
  26 +
  27 +
  28 +- (void)initCNLiveMsgToolsWithAppKey:(NSString *)appKey appId:(NSString *)appId;
  29 +
  30 +
  31 +- (void)onLineWithMsgToolsInfoId:(NSString *)infoId
  32 + infoName:(NSString *)infoName
  33 + infoUrl:(NSString *)infoUrl
  34 + success:(void (^)(NSString *toolsId))successBlock
  35 + error:(void (^)(NSInteger errors))errorBlock;
  36 +
  37 +
  38 +- (void)justOnLineSuccess:(void (^)(NSString *toolsId))successBlock
  39 + error:(void (^)(NSInteger errors))errorBlock;
  40 +
  41 +
  42 +- (void)stealthCNLiveMsgTools;
  43 +
  44 +
  45 +- (void)offLineCNLiveMsgTools:(BOOL)isReceivePush;
  46 +
  47 +
  48 +- (void)gatherTogether:(NSString *)targetId
  49 + messageCount:(int)messageCount
  50 + success:(void (^)(NSString *targetId))successBlock
  51 + error:(void (^)(NSInteger errors, NSString *targetId))errorBlock;
  52 +
  53 +
  54 +- (void)gatherIfNullCreate:(NSString *)targetId
  55 + messageCount:(int)messageCount
  56 + success:(void (^)(NSString *targetId))successBlock
  57 + error:(void (^)(NSInteger errors, NSString *targetId))errorBlock;
  58 +
  59 +
  60 +- (void)gatherTogether:(NSString *)targetId
  61 + isCreate:(BOOL)isCreate
  62 + messageCount:(int)messageCount
  63 + success:(void (^)(NSString *targetId))successBlock
  64 + error:(void (^)(NSInteger errors, NSString *targetId))errorBlock;
  65 +
  66 +
  67 +- (void)disperse:(NSString *)targetId
  68 + success:(void (^)(NSString *targetId))successBlock
  69 + error:(void (^)(NSInteger errors, NSString *targetId))errorBlock;
  70 +
  71 +
  72 +- (void)sendCarrier:(NSString *)carrier
  73 + type:(NSInteger)type
  74 + targetId:(NSString *)targetId
  75 + success:(void (^)(NSString *carrier, NSString *targetId, NSInteger type, NSString *infoId, NSString *infoName, NSString *infoUrl))successBlock
  76 + error:(void (^)(NSInteger errors, NSString *targetId, NSInteger type))errorBlock;
  77 +
  78 +
  79 +- (NSInteger)getOnLineStatus;
  80 +
  81 +
  82 +- (BOOL)judgeLoginStatus;
  83 +
  84 +
  85 +- (NSArray *)getLatestCarriers:(NSInteger)type targetId:(NSString *)targetId count:(int)count;
  86 +
  87 +
  88 +
  89 +@end
... ...
CNLivePlayerSDKTest/CNLiveMsgTools.framework/Info.plist 0 → 100644
No preview for this file type
CNLivePlayerSDKTest/CNLiveMsgTools.framework/RCConfig.plist 0 → 100644
No preview for this file type
CNLivePlayerSDKTest/CNLiveMsgTools.framework/en.lproj/RongCloudKit.strings 0 → 100644
No preview for this file type
CNLivePlayerSDKTest/CNLiveMsgTools.framework/release_notes_ios.txt 0 → 100755
  1 +Platform: iOS
  2 +Version: 2.8.6 Stable
  3 +Date:2017/02/15
  4 +
  5 +Changing log:
  6 +
  7 +2.8.6 Stable
  8 +-------------------------------
  9 +1、优化并修复了一些偶现的 BUG,增强了稳定性。
  10 +2、增加了聊天室连接状态的监听。
  11 +3、更新红包 SDK。
  12 +4、更新表情 SDK。
  13 +5、优化了 VoIP 部分逻辑。
  14 +
  15 +2.8.5 Dev
  16 +-------------------------------
  17 +1、增加了 VoIP 网络质量回调接口。
  18 +2、增加了小能客服。
  19 +3、优化了 imageCell 和 locationCell。
  20 +4、优化了相册加载速度。
  21 +5、修改了日志格式。
  22 +6、修改了聊天室心跳机制,加入聊天室后开启心跳。
  23 +7、修复了表情区域 ,下载、删除动态表情时,Tab 顺序错乱的问题。
  24 +8、删除了音视频录制接口。
  25 +9、更新了红包 SDK。
  26 +10、进行了多 cmp 连接优化。
  27 +
  28 +2.8.4 Stable
  29 +-------------------------------
  30 +1、客服增加超时提醒配置功能。
  31 +2、修复了发送图片和文件时没有返回 messageUId 的问题。
  32 +3、修复了一些偶现的 BUG,增强了稳定性。
  33 +
  34 +
  35 +2.8.3 Stable
  36 +-------------------------------
  37 +1、优化了群组通知的解析问题。
  38 +2、修复了一些UI细节。
  39 +
  40 +2.8.2 Dev
  41 +-------------------------------
  42 +1、针对苹果ATS的策略进行了适配。
  43 +如果您手动管理依赖,需要在 IMKit 的工程中增加 SafariServices.framework 引用;如果您使用 CocoaPods,请使用 RongCloudIM 新的 spec。
  44 +您可以根据您App的迭代情况,开启和设置https,具体可以参考官网文档。
  45 +2、优化了会话列表自定义 Cell 的 UI 细节。
  46 +
  47 +2.8.1 Stable
  48 +-------------------------------
  49 +1、修复了某些机型上阅读回执的显示问题。
  50 +2、优化了会话列表的刷新。
  51 +
  52 +2.8.0 Dev
  53 +-------------------------------
  54 +1、会话列表、会话界面的重构。
  55 +2、输入法表情、加号区域的重构。
  56 +3、增加了消息搜索功能,现在您可以进行消息搜索了。马上试用吧。
  57 +4、群消息回执增加了详情,现在您可以知道哪些人看过消息,也能知道哪些人没有看过消息了。
  58 +5、增加了文件消息发送过程中的取消功能。
  59 +6、我们将日志进行了标准化,并且支持您通过接口访问。
  60 +7、还修复了很多的小问题。
  61 +
  62 +2.7.3 Stable
  63 +-------------------------------
  64 +1、优化了消息的时间和状态显示
  65 +2、优化了文本超链接的显示效果
  66 +
  67 +2.7.2 Stable
  68 +-------------------------------
  69 +1、修复了几个微小的 BUG。
  70 +
  71 +2.7.1 Dev
  72 +-------------------------------
  73 +1、增加了群组、讨论组消息阅读状态功能,发送一条文本消息后,可查看该消息的阅读用户数。
  74 +2、优化多端群组、讨论组未读消息数同步功能。
  75 +3、历史消息云存储功能,更改为通过导航下发配置控制功能是否开启,去掉了 IMKit 中的开关。
  76 +
  77 +2.7.0 Dev
  78 +-------------------------------
  79 +1、新增了文件消息功能,消息标识为 RC:FileMsg ,消息类名 FileMessage ,需要在”+“号区添加功能后才能使用。
  80 +2、新增了群组、讨论组消息回执功能。
  81 +3、新增了 VoIP 录制功能,录制后文件会自动存储到服务器。
  82 +4、VoIP 支持视频分辨率设置功能。
  83 +5、针对历史消息云存储服务,在 IMKit 中实现了获取历史消息后本地自动存储功能,在 IMLib 中调用获取云端历史消息接口,也会自动存储到本地数据库中。
  84 +6、优化了会话列表及会话中时间显示规则。
  85 +7、对会话界面的 UI 显示样式进行了优化。
  86 +
  87 +2.6.11 Stable
  88 +-------------------------------
  89 +1、这个版本我们完整的适配了 iOS 10。苹果的各项策略总是在不断变更,我们会根据其变化第一时间对 SDK 进行升级。对于近期要发布 App 的客户,我们建议您升级到这个版本。
  90 +2、实时地理位置共享功能,从收费使用变为免费,默认功能打开,请您参考我们的源码来实现。未在源代码里实现该功能的用户不受此次升级影响。
  91 +
  92 +2.6.10 Stable
  93 +-------------------------------
  94 +1、从 8 月 9 日开始,因为苹果针对 iOS10 更新了私有接口审核的标准,导致我们一个内部函数因为重名而违规。会造成在最近几天内提交 App Store 的申请被拒,我们紧急更新了这个版本。已经上线的客户不受影响。您在升级的时候也不需要进行任何接口改动。
  95 +2、针对特别的海外客户和专有部署客户优化,增加一个针对导航的解析功能。普通客户不受影响。
  96 +
  97 +2.6.9 Stable
  98 +-------------------------------
  99 +1、优化了 @ 消息的细节,增加了国际化。
  100 +2、修复了在有 1 万条离线消息以上的情况下,收消息比较慢的问题。解决后 1 万条以上的离线消息可以在 1 分钟以内接收完毕。
  101 +
  102 +2.6.8 Dev
  103 +-------------------------------
  104 +1、群组、讨论组中增加了 @ 功能
  105 +2、增加了消息撤回功能
  106 +3、增加了客服技能组功能
  107 +
  108 +2.6.7 Stable
  109 +-------------------------------
  110 +1、为了美化,进行了一些细微的 UI 更新,包括聊天界面,消息气泡背景,边距等等。并不影响集成使用。
  111 +
  112 +2.6.6 Stable
  113 +-------------------------------
  114 +1、对超长或超宽的图片消息,进行了优化,显示更加美观清晰。
  115 +2、对发送地理位置、会话列表等界面的 UI 设计进行了细微的更新以确保美观。
  116 +
  117 +2.6.5 Stable
  118 +-------------------------------
  119 +1、这个版本主要对 UI 交互进行了一些优化,包括对地理位置消息的图片,图片选择器,输入区域等等。
  120 +
  121 +2.6.4 Stable
  122 +-------------------------------
  123 +1、配合融云的 IM 软件 SealTalk 的发布,对 IMKit 的 UI 进行了一些细节优化,增强了一些体验。不影响您的客户使用。
  124 +2、优化了草稿在会话列表中的显示。
  125 +3、优化了聊天室拉取大量消息时的响应速度。
  126 +4、增加了一个错误码 30015 (RC_CONN_OVERFREQUENCY),如果频繁的调用 connect,会返回此错误码。您只需要调用 connect 函数一次即可。
  127 +
  128 +2.6.3 Stable
  129 +-------------------------------
  130 +1、优化重连逻辑,增强网络连接的可靠性。
  131 +2、修改了一些小的的 UI 问题。
  132 +
  133 +2.6.2 Dev
  134 +-------------------------------
  135 +1、在 2.6.0 版本上出现了几例运营商网络劫持导致连接失败的报告,在这个版本上进行了修复。
  136 +
  137 +2.6.1 Dev
  138 +-------------------------------
  139 +1、提升了用户信息缓存的性能。
  140 +
  141 +
  142 +2.6.0 Dev
  143 +-------------------------------
  144 +1、增加了用户信息缓存,如果您的 App 没有本地用户信息的缓存,将很大的节省您的开发量,同时支持离线缓存,性能更好。使用的方法没有改变。
  145 +2、优化了图片选择器的 UI 功能。
  146 +3、全面增加了对 HTTPS 的支持。
  147 +4、针对消息量非常大的情况下,性能进行了优化。
  148 +5、对客服的业务进行了一些优化。
  149 +
  150 +
  151 +2.5.2 Stable
  152 +-------------------------------
  153 +1、针对 iOS9 以上,支持 IPv6。请注意苹果规定从6月1号起,提交到 App Store 的版本都必须支持 IPv6-only 网络,您需要升级到这个版本。
  154 +2、针对消息量非常大的聊天室进行优化,在网络出错情况下减少了等待时间更快速的自动重连。不影响聊天室以外的场景。
  155 +
  156 +
  157 +2.5.1 Stable
  158 +-------------------------------
  159 +1、优化了部分客服业务的功能。
  160 +2、修复了一个小概率问题,当数据库操作出现意外问题的时候,连接会主动断开。再次重连后可以继续使用。以确保不会因为数据库操作异常而丢失消息。
  161 +
  162 +2.5.0 Stable
  163 +-------------------------------
  164 +1、解决了一个与第三方库冲突问题。
  165 +2、优化了会话列表在 iOS7 及以下系统中 UI 界面的显示效果。
  166 +
  167 +2.4.11 Stable
  168 +-------------------------------
  169 +1、对客服业务进行了小幅度的优化。
  170 +
  171 +2.4.10 Dev
  172 +-------------------------------
  173 +1、发布了新版本的客服界面,请参考开源代码的 RCDCustomServiceViewController 来实现您的客服。新版本客服在性能功能上得到大幅优化,并且您可以自行配置您的界面。之前版本的客服界面仍然兼容。
  174 +2、RCReceivedStatus 增加一个属性 ReceivedStatus_RETRIEVED。表示该消息在当前端离线期间,已经被其他端收取过。您可以根据这个状态更新您的 UI 界面,比如已经被收取过就不再弹出提示。如果您开通了多端登录,请注意您的判断条件,对于没有开通多端同步的用户可以忽略。
  175 +3、再次提高了聊天室的性能。尤其优化了超大型聊天室的消息性能。
  176 +4、同时修复了功能性能上的一些问题。
  177 +
  178 +2.4.9 Dev
  179 +-------------------------------
  180 +1、修复 VoIP 有时显示用户信息错误的问题,修复有时连续拨打 VoIP 不能很好接通的问题。
  181 +2、优化了一下会话界面消息体显示。
  182 +3、增加接口,getMessageByUId,从消息的唯一 ID 获得消息类。
  183 +
  184 +
  185 +2.4.8 Stable
  186 +-------------------------------
  187 +1、富文本消息修复了一个问题,使修改颜色正常起作用。
  188 +2、修复了一个短时间内连续多次点击发送消息,有的消息会不显示的问题。
  189 +3、优化了后台自动重连时的性能。
  190 +
  191 +
  192 +2.4.7 Stable
  193 +-------------------------------
  194 +1、消息阅读状态和对方正在输入状态等功能提交到稳定版。
  195 +2、修复了一些多端同步和发件箱功能引起的问题。
  196 +
  197 +
  198 +2.4.6 Dev
  199 +-------------------------------
  200 +1、新增消息阅读状态功能。发送端可以看到接收端是否阅读了该消息,当前只支持单聊。
  201 +2、新增对方正在输入状态功能。动态显示对方的输入状态,当前只支持单聊。
  202 +3、消息多端同步增加发件箱功能,发送端发出的消息也会被其他端拉取下来。
  203 +4、语音消息的最大长度可以设置,比如您可以设置为您的客户最多只能录制并发送 30 秒的语音,默认是 60 秒。
  204 +
  205 +2.4.5 Stable
  206 +-------------------------------
  207 +1、略微增强了聊天室的性能。修复了一个问题,当客户端同一个 id 加入两个不同的聊天室时,增加了逻辑避免出现显示错误。
  208 +2、当发送消息失败时,如果原因是网络连接已经断开,会自动做一次重连。开发者不需要对此修改做额外处理。
  209 +
  210 +2.4.4 Stable
  211 +-------------------------------
  212 +1、增加读取消息接口getMessage:,可以根据messageId来读取消息。
  213 +2、优化了聊天室逻辑,确保在网络较差情况下不会聊天室掉线。
  214 +3、增加查询聊天室信息接口getChatRoomInfo,您可以查询聊天室成员数目和部分成员ID。
  215 +
  216 +2.4.3 Stable
  217 +-------------------------------
  218 +
  219 +1、增加 messageUId(Universal Id),您可以通过该 UId 匹配一条具体的消息。
  220 +
  221 +2、增加聊天室接口 JoinExistChatroom,加入一个存在的聊天室,如果聊天室不存在则加入不成功。
  222 +
  223 +
  224 +2.4.2 Stable
  225 +-------------------------------
  226 +
  227 +1、增加了聊天室(Chatroom)禁言、封禁两个功能。请通过 Server API 使用。当前用户被禁言或者被封禁后客户端会显示提示。
  228 +
  229 +
  230 +
  231 +2.4.1 Stable
  232 +-------------------------------
  233 +
  234 +1、文本消息和富文本消息,可以通过 RCAttributedLable 的 attributedStrings 属性,给一些文字添加自定义的事件。请参考代码注释中的示例代码。
  235 +2、修复了一个遗留问题,如果您通过 enableMessageAttachUserInfo 在每条消息里携带用户信息,在 IMKit 里会强制显示该用户信息,请打开了这个开关的用户注意。
  236 +
  237 +
  238 +2.4.0 Stable
  239 +-------------------------------
  240 +
  241 +1、修复了一个因为在 IMKit 里直接调用 SendMessage ,极特殊状态下因为网络速度导致返回太快,发送状态没有更新的问题。
  242 +
  243 +2、增加了一种不保存、不计数的 RCCommandMessage(ObjectName 为 RC:CmdMsg),您需要这种类型的消息时可以直接使用,不需要再自定义。
  244 +
  245 +
  246 +
  247 +
  248 +2.3.9 Stable
  249 +-------------------------------
  250 +1、增加功能:未读的语音消息点击后默认连续播放。
  251 +2、增加功能:会话列表界面每条会话的头像右上角的未读数显示可以配置,可以改成红点而不显示未读数。
  252 +3、提高了 UI 显示性能。
  253 +
  254 +2.3.8 Stable
  255 +-------------------------------
  256 +
  257 +1、在 IMKit 中,重新封装了 sendMessage 方法,实现了您在使用这个方法发送消息后自动更新 UI 界面。
  258 +
  259 +2、增加未注册的消息自定义显示功能,通过设置 showUnkownMessage 为 YES,实现在 App 中提示“当前版本不支持查看此消息”。默认值为 NO,没有该需求的用户不用做任何更改。
  260 +
  261 +3、美化了公众服务相关菜单和界面的 UI 展示。
  262 +
  263 +
  264 +2.3.7 Stable
  265 +-------------------------------
  266 +1、新功能语音消息点击后自动播放,增加一个配置可以关闭和打开该功能。
  267 +2、优化了输入框区域点击表情和键盘图片后的交互过程。
  268 +3、美化了公众服务图文消息的显示效果。
  269 +
  270 +
  271 +2.3.6 Stable
  272 +-------------------------------
  273 +1、增加功能:未读的语音消息点击后默认连续播放。
  274 +2、增加功能:会话列表界面每条会话的头像右上角的未读数显示可以配置,可以改成红点而不显示未读数。
  275 +3、提高了 UI 显示性能。
  276 +
  277 +2.3.5 Stable
  278 +-------------------------------
  279 +1、略微调整了网络状态栏、选择图片按钮的布局设计,以更加美观。
  280 +
  281 +
  282 +
  283 +
  284 +2.3.4 Stable
  285 +-------------------------------
  286 +1、增加了语音消息和图片消息质量的配置文件,支持用户在融云平台支持的范围内配置。
  287 +
  288 +2、优化了输入界面的显示效果。
  289 +
  290 +3、增加了稳定性。
  291 +
  292 +
  293 +
  294 +
  295 +2.3.3 Stable
  296 +-------------------------------
  297 +
  298 +1、优化了会话界面下 UI 显示效率。
  299 +2、增加了对 iOS6.0 系统上的一些问题的修改。
  300 +3、修改了iOS7.0 下,当未读消息非常多的时候,反复下拉消息有一定概率崩溃的问题。
  301 +4、增加了对 XCode7 上的 Archive 支持。
  302 +
  303 +
  304 +
  305 +
  306 +2.3.2 Stable
  307 +-------------------------------
  308 +
  309 +1、增加了一个 ImageMessage 的构造方法,从这个版本起可以支持通过参数发送原图。
  310 +
  311 +2、增加群组禁言功能,请配合 Server API 使用。
  312 +
  313 +3、修复了当取消关注公众服务号同时默认删除公众号会话时的一个显示错误。
  314 +
  315 +4、修复了扩展区域功能多于 8 个时,左右滑动时的问题。少于 8 个并不会有问题。
  316 +
  317 +5、略微修改了气泡和名称的布局使其对齐。
  318 +
  319 +6、修复了 VoIP 的问题,目前在 iOS 各版本上使用正常。
  320 +
  321 +2.3.1 Dev
  322 +-------------------------------
  323 +
  324 +1、增加了对 BitCode 编译选项,更好的支持XCode7和iOS9。
  325 +2、将第三方开源语音库 libopencore-armnb.a 独立出来,以方便您同时集成其他第三方组件时避免冲突,请注意把这个库单独包含到您的工程里。
  326 +3、增加了远程通知数据统计,使用 recordLaunchOptionsEvent,recordRemoteNotificationEvent,recordLocalNotificationEvent,您可以将用户点击系统推送的数据记录到融云的后台。
  327 +
  328 +2.3.0 Stable
  329 +-------------------------------
  330 +1、当您需要使用公众服务会话时,您需要在集成会话列表时,主动在 onSelectedTableRow 中添加 RC_CONVERSATION_MODEL_TYPE_PUBLIC_SERVICE,这是为了实现一些用户的自定义需求,请参考 Demo App 源码。
  331 +2、开放了公众号的图文消息点击事件,覆写 didTapImageTxtMsgCell 方法。可以实现自定义跳转。
  332 +3、替换了一个有可能跟其他 SDK 产生冲突的库。
  333 +4、实现了一些新客户的需求。
  334 +
  335 +2.2.11 Dev
  336 +-------------------------------
  337 +
  338 +1、修复了客户反馈的一些问题,增强了稳定性。
  339 +
  340 +
  341 +
  342 +
  343 +2.2.10 Stable
  344 +-------------------------------
  345 +
  346 +1、增加了对系统会话未读消息的计数功能。
  347 +2、优化了公众服务号,单图文、多图文界面的显示。
  348 +3、增加了接口 sendImageMessage:pushContent:appUpload: ,可实现发送图片消息时将图片上传到自已的服务器发送。
  349 +4、会话中阅读新消息时,现实新消息与历史消息分界线提示功能。
  350 +5、增加了 Web 端和手机端用户同时在线状态下,Web 端发送信息手机端能同步发送的功能。
  351 +6、修改 IMKit 和 IMLib 支持最低版本号为 iOS 6.0。
  352 +
  353 +
  354 +2.2.9 Dev
  355 +-------------------------------
  356 +1、修复了轻微的界面问题。
  357 +
  358 +2.2.8 Stable
  359 +-------------------------------
  360 +1、实时地理位置共享功能发布,您可以在融云的 Demo App 上体验该功能。来试试通过 RCRealTimeLocationManager 实现您 App 自己的实时位置共享吧。
  361 +2、修复了一些界面显示相关的小问题。
  362 +
  363 +2.2.7 Stable
  364 +-------------------------------
  365 +1、在会话界面上下滚动时,如果收到新消息,不会自动显示新消息而会停留在当前位置。
  366 +
  367 +2、增加了录音时来电切到后台的处理。
  368 +
  369 +3、解决了一个在 iOS6.0 上的兼容问题。
  370 +
  371 +
  372 +
  373 +2.2.6 Stable
  374 +-------------------------------
  375 +1、开放 appendAndDisplayMessage,用户可以自己加入消息并刷新会话界面。
  376 +
  377 +2、为头像增加长按点击事件。
  378 +
  379 +3、修复了一个文本消息不响应点击事件的 BUG。
  380 +
  381 +4、修复了一个图片库界面显示不美观的问题。
  382 +
  383 +5、修复了一个公众服务的内置浏览器问题。
  384 +
  385 +
  386 +2.2.5 Stable
  387 +-------------------------------
  388 +1、增加了正在连接中的状态。
  389 +2、增强了保护,对于通过 Server API 发送消息传入错误参数导致的问题全面保护。
  390 +3、位置消息增加长按删除。
  391 +4、设置消息免打扰由于网络原因失败时会弹出提示。
  392 +5、增加了界面上的一些定制化功能。
  393 +6、保护了一个发送系统广播时,由于没有针对发送广播的 id 设置用户信息,会导致本地通知不提示的问题。
  394 +7、共享服务平台自定义菜单的发送消息功能已经上线。
  395 +
  396 +2.2.4 Stable
  397 +-------------------------------
  398 +1、删除 reconnect 方法。使用融云 SDK 时,connect 只需要执行一次。对于有场景需要重连时,比如 Token 过期,请使用 connect 方法。其他异常请不要或尽量避免调用重连。
  399 +2、修改了一些界面布局的问题,进行了界面优化。
  400 +3、修改了一个发送图片不显示进度条的问题。
  401 +
  402 +2.2.3 Dev
  403 +-------------------------------
  404 +
  405 +1、删除 reconnect 方法,请不要使用它进行重连。connect 只需要执行一次。对于有特殊业务场景强烈需要重连的用户,请使用 connect 方法。
  406 +2、修改了 joinChatRoom 接口,当加入聊天室时,传入 messageConunt 为 -1 表示不拉取历史消息。
  407 +3、为一些客户的定制化需求优化了显示相关的功能。
  408 +
  409 +2.2.2 Stable
  410 +-------------------------------
  411 +
  412 +1、initWithAppKey 去掉参数 DeviceToken,因为初始化阶段很难获得 DeviceToeken。
  413 +
  414 +2、优化了 setDeviceToken 方法,增加了缓存。
  415 +
  416 +3、增强了重连机制,增加了一些特殊的网络错误的自动重连。
  417 +
  418 +4、修复了一些 iOS 6 系统下的异常。
  419 +
  420 +5、修复了客户反馈的一些异常并增强了稳定性。
  421 +
  422 +
  423 +2.2.1 Dev
  424 +-------------------------------
  425 +
  426 +1、initWithAppKey 去掉参数 DeviceToken,因为初始化阶段很难获得 DeviceToeken,同时优化了 setDeviceToken,做了内部缓存,以帮用户存储正确的值。
  427 +
  428 +2、增强了重连机制。
  429 +
  430 +
  431 +
  432 +2.2.0 Stable
  433 +-------------------------------
  434 +
  435 +1、增加了公众服务自定义菜单。
  436 +
  437 +2、为 sendMessage 增加一个 pushExtra 字段,可以附加消息到 APNS 推送里。
  438 +
  439 +3、增加了 insertMessage 接口。
  440 +
  441 +4、继续优化了连接稳定性和重连机制。
  442 +
  443 +5、为了一些客户定制化需求优化了功能。
  444 +
  445 +6、修复了各种渠道反馈的一些小概率异常和崩溃问题。
  446 +
  447 +
  448 +2.1.4 Stable
  449 +-------------------------------
  450 +
  451 +1.增加了富文本消息的长按事件。
  452 +2.修改了图文消息的布局问题。
  453 +3.会话列表头像设置,放开大小限制。
  454 +4.解决了收到推送后跳转到聊天界面以后,如果有其他人或者群发来消息,导航栏的返回按钮就失效的问题。
  455 +5.修复了 2.1.3 版本上因为修改图片缓存导致发送图片消息会导致无法取到本地图片的问题。
  456 +6.修改了 tokenIncorrect 逻辑,增加了一次场景更准确的反馈该错误信息给客户。
  457 +7.增加了信令用于同步 WebSDK 的会话列表信息。
  458 +8.修复了一个可能导致无法拉取离线消息的小概率问题。
  459 +
  460 +2.1.3 Stable
  461 +-------------------------------
  462 +
  463 +1、Emoji 作为资源文件,可以自定义 Emoji 表情。
  464 +2、修改了 RCContactNotificationMessage 消息解析的一个问题
  465 +3、修改了会话列表最后一条消息显示的一个问题。
  466 +4、修改讨论组用户名显示的一个问题
  467 +5、修改了因为回调指针为空可能导致崩溃的一个底层问题。
  468 +
  469 +
  470 +
  471 +2.1.2 Stable
  472 +-------------------------------
  473 +
  474 +1、增加了一些网络错误状态发生后重连的次数,更容易重连。
  475 +
  476 +2、修改了缓存文件存储的系统路径。
  477 +
  478 +3、增加了公众服务的草稿。
  479 +
  480 +4、Emoji库可以通过资源包替换。
  481 +
  482 +5、修改了上一个版本出现的可能会导致消息发送时一直发不出去的问题。
  483 +
  484 +6、修改了发送语音过程中的一些界面问题。
  485 +
  486 +
  487 +
  488 +
  489 +2.1.1 Stable
  490 +-------------------------------
  491 +
  492 +1、增加了对 Apple WatchKit 的支持,现在您可以直接使用融云的 IMlib 实现 Apple Watch App,我们同时开源了 Demo App。
  493 +
  494 +2、增加了单个 App 内群组的上限,旧的版本不能超过 300 个群组。
  495 +
  496 +3、解决了一些界面在 iOS7.0 上不能使用并崩溃的问题。
  497 +
  498 +4、解决了连续收到多条消息,会话列表刷新错误的问题。
  499 +
  500 +5、解决了自定义消息透传的问题。
  501 +
  502 +6、修复了一些语音消息的功能和界面问题,增加了点击语音消息可以停止语音播放的功能。
  503 +
  504 +7、增加了一些消息的点击事件。
  505 +
  506 +8、当您不在群组/讨论组/聊天室内,而又能进入界面发起消息是,给出文字提示。
  507 +
  508 +9、解决了一个当自动重连时有可能会导致的不发起连接回调的问题。
  509 +
  510 +10、增加了接口 refreshUserInfoCache 和 refreshGroupInfoCache 用于刷新用户信息缓存。
  511 +
  512 +
  513 +
  514 +2.1.0 Stable
  515 +-------------------------------
  516 +1、增强了针对网络切换、网络不稳定时的连接稳定性问题。
  517 +
  518 +2、修改了当网络出现问题,由于消息时间错误导致消息排列错误的问题。
  519 +
  520 +3、修改了断网再连接导致小概率 crash 的问题。
  521 +
  522 +4、修改了会话界面消息时间显示不准确的问题。
  523 +
  524 +5、修改了发送接收表情,有时候显示为空的问题。
  525 +
  526 +6、修复了自定义消息透传的问题。
  527 +
  528 +7、修复了一些对低版本iOS的兼容问题。
  529 +
  530 +8、优化了网络连接缓存机制。
  531 +
  532 +2.0.5 Dev
  533 +-------------------------------
  534 +1、增加了消息置顶之后的显示效果。
  535 +2、增加了新消息提醒打开关闭的功能。
  536 +3、增加了“该账号已在另外一台设备上登录”提示。
  537 +4、修复了会话列表的一些时间顺序和显示问题。
  538 +5、优化了断网和弱网络下的重连机制,更快的从网络中恢复。
  539 +6、修复了小概率情况下收到消息后因为时间错误,导致消息被排列到错误的问题。
  540 +7、修复了一些测试过程中出现的小概率崩溃问题。
  541 +8、增加了连接缓存功能,增强了连接稳定性。
  542 +
  543 +2.0.4 Dev
  544 +-------------------------------
  545 +1、增加了连接稳定性,修复了从后台进入前台后显示网络连接不可用的问题。
  546 +2、修复了一些小概率 Crash 问题。
  547 +3、修复了时间显示错误的问题。
  548 +4、增强了内存优化。
  549 +5、修复了录音和播放录音会跟系统播放冲突的问题。
  550 +6、增加了 DNS 缓存功能,以增强网络连接稳定性。
  551 +
  552 +2.0.3 Dev
  553 +-------------------------------
  554 +1、增加了文本消息中连接高亮显示功能。
  555 +2、修复了会话界面输入法功能的显示问题。
  556 +3、解决了讨论组清空历史消息时会把此讨论组也删除的问题。
  557 +4、解决了系统播放音乐时,收到信息播放提示音之后音乐不继续播放的问题。
  558 +5、解决了发送图片,发送端点击不能放大缩小的问题。
  559 +6、修复了一些可能会显示网络连接不可用的问题。
  560 +
  561 +2.0.2 Dev
  562 +-------------------------------
  563 +1、美化了一些 UI 界面显示。
  564 +2、修复了输入框输入大量字符显示相关的问题。
  565 +3、修复了接收未注册自定义消息显示错误的问题。
  566 +4、解决了接收 API 发送的图文混排消息显示错误的问题。
  567 +5、当手机中无照片时,点击相册默认会提示“无视频和照片”。
  568 +6、修复了发送 60s 语音,有一定概率崩溃的问题。
  569 +7、修复了一些业务层稳定性问题。
  570 +8、修复了在其它页面来新消息没有铃声提示的问题。
  571 +9、修复了发送表情后,点击发送按钮会发送空消息的问题。
  572 +10、解决了图片预览页图片不能放大和缩小的问题。
  573 +
  574 +2.0.1 Dev
  575 +-------------------------------
  576 +1、增强了 UI 显示效果,修改了一些UI问题。
  577 +2、增加了自定义消息展示的接口,更方便的自定义自己消息类型展现。
  578 +3、修复了发送图像,发送端点击缩略图无法打开问题。
  579 +4、修改了一些内存泄露问题。
  580 +
  581 +2.0.0 Dev
  582 +-------------------------------
  583 +1、重构了会话列表界面和会话界面的架构,支持丰富的界面自定义。
  584 +2、支持会话列表的自定义,聚合非聚合显示,支持插入用户自定义数据和展现。
  585 +3、支持自定义会话界面,预置了九种输入框界面。
  586 +4、支持自定义消息的展现,采用自动布局,可以自定义消息界面的展现。
  587 +5、开放了更多的 API 接口和监听。
  588 +6、优化了协议栈的重连机制,现在 App 从断线状态恢复重连将更快。
  589 +7、优化了数据库性能,消息的读写速度将更快。
  590 +8、支持搜索关注公众账号,支持公众账号的详情展现。
  591 +9、支持公众服务多图文消息、单图文消息的展现。
  592 +10、增加了对 Apple Watch 的内置支持。
... ...
CNLivePlayerSDKTest/CNLiveMsgTools.framework/zh-Hans.lproj/RongCloudKit.strings 0 → 100644
No preview for this file type
CNLivePlayerSDKTest/CNLivePlayerSDK.framework/CNLivePlayerSDK
No preview for this file type
CNLivePlayerSDKTest/CNLivePlayerSDK.framework/Headers/CNLiveAudioCapture.h 0 → 100644
  1 +//
  2 +// CNLiveAudioCapture.h
  3 +// CNLivePlayerSDKDemo
  4 +//
  5 +// Created by iOS on 17/2/27.
  6 +// Copyright © 2017年 雷浩杰. All rights reserved.
  7 +//
  8 +
  9 +#import <Foundation/Foundation.h>
  10 +
  11 +@interface CNLiveAudioCapture : NSObject
  12 +
  13 +/**
  14 + @abstract 是否有耳机麦克风可用
  15 + @return 是/否有耳机麦克风
  16 + */
  17 ++ (BOOL)isHeadsetPluggedIn;
  18 +
  19 +/**
  20 + @abstract 是否播放采集的声音 (又称"耳返")
  21 + @warning 如果在没有插入耳机的情况下启动, 容易出现很刺耳的声音
  22 + */
  23 +@property(nonatomic, assign) BOOL bPlayCapturedAudio;
  24 +
  25 +/**
  26 + @abstract 设置mic采集的声音音量
  27 + @discussion 调整范围 0.0~1.0
  28 + */
  29 +@property(nonatomic, assign) Float32 micVolume;
  30 +
  31 +/**
  32 + @abstract 混响类型
  33 + @discussion 目前提供了4种类型的混响场景, type和场景的对应关系如下
  34 +
  35 +- 0 关闭
  36 +- 1 录音棚
  37 +- 2 KTV
  38 +- 3 小舞台
  39 +- 4 演唱会
  40 +*/
  41 +@property(nonatomic, assign) int reverbType;
  42 +
  43 +@end
... ...
CNLivePlayerSDKTest/CNLivePlayerSDK.framework/Headers/CNLiveBeautifyFaceFilter.h 0 → 100644
  1 +//
  2 +// CNLiveBeautifyFaceFilter.h
  3 +// CNLivePlayerSDKDemo
  4 +//
  5 +// Created by iOS on 17/3/2.
  6 +// Copyright © 2017年 雷浩杰. All rights reserved.
  7 +//
  8 +
  9 +#import <Foundation/Foundation.h>
  10 +#import "CNLiveTypeDef.h"
  11 +#import <UIKit/UIKit.h>
  12 +
  13 +/**
  14 + * 美颜((默认旧美颜,参数为0.5))
  15 + */
  16 +
  17 +@interface CNLiveBeautifyFaceFilter : NSObject
  18 +
  19 +/**
  20 + @abstract CNLiveBeautyTypeSpecial 美颜特效类型,需先设置CNLiveBeautyType为CNLiveBeautyTypeSpecial
  21 + */
  22 +@property (nonatomic, assign) CNLiveSpecialEffects curEffectIdx; //美颜类型
  23 +
  24 +/**
  25 + @abstract 美颜类型
  26 + @param beautyType 类型
  27 + */
  28 +- (void)setBeautyType:(CNLiveBeautyType)beautyType;
  29 +
  30 +/**
  31 + @abstract 美颜参数调节
  32 + @param grindRatio 磨皮
  33 + @param whitenRatio 美白
  34 + @param intensity 特效
  35 + */
  36 +- (void)filterAdjustingParameterWithGrindRatio:(CGFloat)grindRatio
  37 + whitenRatio:(CGFloat)whitenRatio
  38 + intensity:(CGFloat)intensity;
  39 +
  40 +
  41 +@end
... ...
CNLivePlayerSDKTest/CNLivePlayerSDK.framework/Headers/CNLiveGPUStreamerKit.h
... ... @@ -7,34 +7,21 @@
7 7 //
8 8  
9 9 #import <Foundation/Foundation.h>
10   -#import <AVFoundation/AVFoundation.h>
11   -#import <UIKit/UIKit.h>
12   -#import "CNLiveTypeDef.h"
  10 +#import "CNLiveWebcastManager.h"
13 11  
14 12 @interface CNLiveGPUStreamerKit : NSObject
15 13  
16   -/**
17   -@abstract 获取SDK版本号
18   -*/
19   -+ (NSString *)getVersion;
20   -
21 14 #pragma mark - 使用视讯云平台
22 15  
23 16 /**
24 17 @abstract 初始化
25 18 @warning 实例化的对象必须赋值给一个全局变量
26   - @param appId 应用ID
27   - @param appKey 注册后的应用key
28 19 @param activityId 活动ID,确保SP下的唯一性
29 20 @param channelId 主播ID
30 21 @param isHorizontalScreen 屏幕方向,0:垂直即竖屏 /1:水平即横屏 ,默认为1
31   - @param success 用于返回初始化状态(成功)
32   - @param failure 用于返回初始化状态(失败)
33 22 @warning 必传参数
34 23 */
35   --(instancetype)initWithDefaultConfigWithAppId:(NSString *)appId
36   - appKey:(NSString *)appKey
37   - activityId:(NSString *)activityId
  24 +-(instancetype)initWithDefaultConfigWithActivityId:(NSString *)activityId
38 25 channelId:(NSString *)channelId
39 26 isHorizontalScreen:(NSString *)isHorizontalScreen;
40 27  
... ... @@ -99,81 +86,105 @@
99 86 -(instancetype)initWithDefaultConfig;
100 87  
101 88 /**
102   - @abstract 视频分辨率
103   - @discussion width x height ( 此处width始终大于高度,是否竖屏取决于videoOrientation的值 )
  89 + @abstract 获取水印工具
  90 + @discussion 通过它来设置水印图片/文字
104 91 */
105   -@property (nonatomic, assign) CNLiveVideoDimension videoDimension;
  92 +@property (nonatomic, readonly) CNLiveWatermark *watermark;
106 93  
107 94 /**
108   - @abstract 用户定义的视频分辨率
109   - @discussion 当videoDimension 设置为 CNLiveVideoDimension_UserDefine_* 时有效
110   - @discussion 内部始终将较大的值作为宽度 (若需要竖屏,请设置 videoOrientation)
111   - @discussion 宽高都会向上取整为4的整数倍
112   - @discussion 宽度有效范围[160, 1280]
113   - @discussion 高度有效范围[ 90, 720]
  95 + @abstract 获取底层推流工具
  96 + @discussion 通过它来设置推流参数
114 97 */
115   -@property (nonatomic, assign) CGSize videoDimensionUserDefine;
  98 +@property (nonatomic, readonly) CNLiveStreamerBase *streamerBase;
116 99  
117 100 /**
118   - @abstract 视频编码器
119   - @discussion video codec used for encode
  101 + @abstract 获取音频采集工具
120 102 */
121   -@property (nonatomic, assign) CNLiveVideoCodec videoCodec;
  103 +@property (nonatomic, readonly) CNLiveAudioCapture *audioCapture;
122 104  
123 105 /**
124   - @abstract 视频编码起始码率(单位:kbps)
125   - @discussion 开始推流时的视频码率,开始推流后,根据网络情况在 [Min, Max]范围内调节
126   - @discussion 视频码率上调则画面更清晰,下调则画面更模糊
  106 + @abstract 获取美颜工具
127 107 */
128   -@property (nonatomic, assign) int videoInitBitrate;
  108 +@property (nonatomic, readonly) CNLiveBeautifyFaceFilter *beautifyFaceFilter;
  109 +
  110 +#pragma mark - capture & preview settings
129 111  
130 112 /**
131   - @abstract 视频编码最高码率(单位:kbps)
132   - @discussion 视频码率自适应调整的上限, 为目标码率
  113 + @abstract 采集分辨率 (仅在开始采集前设置有效)
  114 + @discussion 参见iOS的 AVCaptureSessionPresetXXX的定义 默认值为AVCaptureSessionPreset640x480
  115 + @discussion 不同设备支持的预设分辨率可能不同, 请尽量与预览分辨率一致
133 116 */
134   -@property (nonatomic, assign) int videoMaxBitrate;
  117 +@property (nonatomic, assign) NSString * capPreset;
135 118  
136 119 /**
137   - @abstract 视频编码最低码率(单位:kbps)
138   - @discussion 视频码率自适应调整的下限
  120 + @abstract 查询实际的采集分辨率
  121 + @discussion 参见iOS的 AVCaptureSessionPresetXXX的定义
139 122 */
140   -@property (nonatomic, assign) int videoMinBitrate;
  123 +- (CGSize) captureDimension;
141 124  
142 125 /**
143   - @abstract 最大关键帧间隔(单位:秒, 默认:3)
144   - @discussion 即GOP长度 画面静止时,隔n秒插入一个关键帧
  126 + @abstract 预览分辨率 (仅在开始采集前设置有效)
  127 + @discussion 内部始终将较大的值作为宽度 (若需要竖屏,请设置 videoOrientation)
  128 + @discussion 宽高都会向上取整为4的整数倍
  129 + @discussion 有效范围: 宽度[160, 1920] 高度[ 90, 1080], 超出范围会取边界有效值
  130 + @discussion 当预览分辨率与采集分辨率不一致时:
  131 + 若宽高比不同, 先进行裁剪, 再进行缩放
  132 + 若宽高比相同, 直接进行缩放
  133 + @discussion 默认值为(640, 360)
145 134 */
146   -@property (nonatomic, assign) int maxKeyInterval;
  135 +@property (nonatomic, assign) CGSize previewDimension;
147 136  
148 137 /**
149   - @abstract 音频编码码率(单位:kbps)
150   - @discussion 音频目标编码码率 (比如48,96,128等)
  138 + @abstract 用户定义的视频 **推流** 分辨率
  139 + @discussion 有效范围: 宽度[160, 1280] 高度[ 90, 720], 超出范围会取边界有效值
  140 + @discussion 其他与previewDimension限定一致,
  141 + @discussion 当与previewDimension不一致时, 同样先裁剪到相同宽高比, 再进行缩放
  142 + @discussion 默认值为(640, 360)
  143 + @see previewDimension
151 144 */
152   -@property (nonatomic, assign) int audiokBPS;
  145 +@property (nonatomic, assign) CGSize streamDimension;
  146 +
  147 +/**
  148 + @abstract 采集及编码视频帧率 (开始采集前设置有效)
  149 + @discussion video frame per seconds 有效范围[1~30], 超出范围会取边界有效值
  150 + @discussion 默认值为15 */
  151 +@property (nonatomic, assign) int videoFPS;
153 152  
154 153 /**
155   - @abstract 启用自动调整码率
156   - @discussion 默认为关闭自动调整码率,开始预览前设置有效
  154 + @abstract 摄像头位置
  155 + @discussion 前后摄像头 默认为前摄像头
157 156 */
158   -@property (nonatomic, assign) BOOL enAutoApplyEstimateBW;
  157 +@property (nonatomic, assign) AVCaptureDevicePosition cameraPosition;
  158 +
159 159  
160 160 /**
161   - @abstract 视频帧率
162   - @discussion video frame per seconds 有效范围[15~30]
  161 + @abstract 获取当前采集设备的指针
  162 + @return AVCaptureDevice* 预览开始前调用返回为nil,开始预览后,返回当前正在使用的摄像头
  163 + @warning 请勿修改摄像头的像素格式,帧率,分辨率等参数,修改后会导致推流工作异常或崩溃
163 164 */
164   -@property (nonatomic, assign) int videoFPS;
  165 +- (AVCaptureDevice *) getCurrentCameraDevices;
165 166  
166 167 /**
167   - @abstract 是否开启美颜
168   - @discussion 默认为开启
  168 + @abstract 采集设备状态
169 169 */
170   -@property (nonatomic, assign) BOOL isOpenImageFilter;
  170 +@property (nonatomic, readonly) CNLiveCaptureState captureState;
  171 +
  172 +FOUNDATION_EXPORT NSString *const CNLiveCaptureStateDidChangeNotification NS_AVAILABLE_IOS(7_0);
  173 +
  174 +#pragma mark - stream settings
  175 +
171 176  
172 177 /**
173   - @abstract 摄像头位置
174   - @discussion 前后摄像头 默认为前摄像头
  178 + @abstract 推流状态
175 179 */
176   -@property (nonatomic, assign) AVCaptureDevicePosition cameraPosition;
  180 +@property (nonatomic, readonly) CNLiveStreamState streamState;
  181 +
  182 +FOUNDATION_EXPORT NSString *const CNLiveStreamStateDidChangeNotification NS_AVAILABLE_IOS(7_0);
  183 +
  184 +/**
  185 + * @abstract 推流错误码,用于指示推流失败的原因
  186 + */
  187 +@property (nonatomic, readonly) CNLiveStreamErrorCode streamErrorCode;
177 188  
178 189 /**
179 190 @abstract 切换摄像头
... ... @@ -190,7 +201,11 @@
190 201 - (void) setTorchMode:(AVCaptureTorchMode)mode;
191 202  
192 203 /**
193   - @abstract 画面朝向描述的是横屏还是竖屏,需要与UI朝向一致,否则会出现画面缺失的情况,第一次设置有效
  204 + @abstract 摄像头朝向
  205 + @discussion 参见UIInterfaceOrientation
  206 + @discussion 竖屏时: width < height
  207 + @discussion 横屏时: width > height
  208 + @discussion 需要与UI方向一致
194 209 */
195 210 - (void) setVideoOrientationBy:(UIInterfaceOrientation)uiOrien;
196 211  
... ... @@ -221,29 +236,57 @@
221 236 - (void) stopStream;
222 237  
223 238 /**
224   - @abstract 获取当前采集设备的指针
225   - @return AVCaptureDevice* 预览开始前调用返回为nil,开始预览后,返回当前正在使用的摄像头
226   - @warning 请勿修改摄像头的像素格式,帧率,分辨率等参数,修改后会导致推流工作异常或崩溃
  239 + @abstract 进入后台: 暂停图像采集
  240 + @discussion 暂停图像采集和预览
227 241 */
228   -- (AVCaptureDevice *) getCurrentCameraDevices;
  242 +- (void) appEnterBackground;
229 243  
230 244 /**
231   - @abstract 采集设备状态
  245 + @abstract 回到前台: 恢复采集
  246 + @discussion 恢复图像采集和预览
232 247 */
233   -@property (nonatomic, readonly) CNLiveCaptureState captureState;
  248 +- (void) appBecomeActive;
234 249  
235   -FOUNDATION_EXPORT NSString *const CNLiveCaptureStateDidChangeNotification NS_AVAILABLE_IOS(7_0);
  250 +#pragma mark - mirror & rotate
236 251  
237 252 /**
238   - @abstract 推流状态
  253 + @abstract 预览设置成镜像模式,默认为NO
239 254 */
240   -@property (nonatomic, readonly) CNLiveStreamState streamState;
  255 +@property (nonatomic, assign) BOOL previewMirrored;
241 256  
242   -FOUNDATION_EXPORT NSString *const CNLiveStreamStateDidChangeNotification NS_AVAILABLE_IOS(7_0);
  257 +/**
  258 + @abstract 推流设置成镜像模式,默认为NO
  259 + */
  260 +@property (nonatomic, assign) BOOL streamerMirrored;
243 261  
244 262 /**
245   - * @abstract 推流错误码,用于指示推流失败的原因
  263 + @abstract 根据UI的朝向旋转预览视图, 保证预览视图全屏铺满窗口
  264 + @param orie 旋转到目标朝向, 需要从demo中获取UI的朝向传入
  265 + @discussion 采集到的图像的朝向还是和启动时的朝向一致
246 266 */
247   -@property (nonatomic, readonly) CNLiveStreamErrorCode streamErrorCode;
  267 +- (void) rotatePreviewTo: (UIInterfaceOrientation) orie;
  268 +
  269 +/**
  270 + @abstract 根据UI的朝向旋转推流画面
  271 + @param orie 旋转到目标朝向, 需要从demo中获取UI的朝向传入
  272 + */
  273 +- (void) rotateStreamTo: (UIInterfaceOrientation) orie;
  274 +
  275 +/**
  276 + @abstract 当前采集设备是否支持自动变焦
  277 + @param point相机对焦的位置
  278 + */
  279 +- (void)focusAtPoint:(CGPoint )point;
  280 +
  281 +/**
  282 + @abstract 当前采集设备是否支持自动曝光
  283 + @param point相机曝光的位置
  284 + */
  285 +- (void)exposureAtPoint:(CGPoint )point;
  286 +
  287 +/**
  288 + @abstract 触摸缩放因子
  289 + */
  290 +@property (nonatomic, assign) CGFloat pinchZoomFactor;
248 291  
249 292 @end
... ...
CNLivePlayerSDKTest/CNLivePlayerSDK.framework/Headers/CNLiveMoviePlayerController.h
... ... @@ -7,29 +7,21 @@
7 7  
8 8 #import <UIKit/UIKit.h>
9 9 #import <MediaPlayer/MediaPlayer.h>
  10 +#import "CNLiveTypeDef.h"
10 11  
11 12 @interface CNLiveMoviePlayerController : NSObject
12 13  
13   -/*
14   - * 获取SDK版本号
15   - */
16   -+ (NSString *)getVersion;
17   -
18 14 #pragma mark - 使用视讯云平台 直接通过节目id播放
19 15 /* 初始化点播播放器 初始化成功后才能对播放器进行设置(如:自动播放、是否开启硬件解码等)和调用准备播放视频方法(prepareToPlay)
20 16 *
21 17 * 当前版本只支持单实例的CNLiveMoviePlayerController对象,多实例将导致播放异常
22 18 *
23   - * appId 在open.cnlive.com网站申请得到的appId
24   - * appKey 在open.cnlive.com网站申请得到的app_key
25 19 * vId 点播视频Id
26 20 * authSuccess 初始化成功block
27 21 * authFailed 初始化失败block 回调一个errorInfo的字典
28 22 *
29 23 */
30   -- (instancetype)initVodPlayWithAppId:(NSString *)appId
31   - appKey:(NSString *)appKey
32   - vId:(NSString *)vId
  24 +- (instancetype)initVodPlayWithVId:(NSString *)vId
33 25 authSuccess:(void(^)(void))authSuccessBlock
34 26 authFailed:(void(^)(NSDictionary *errorInfo))authFailedBlock;
35 27  
... ... @@ -37,18 +29,18 @@
37 29 *
38 30 * 当前版本只支持单实例的CNLiveMoviePlayerController对象,多实例将导致播放异常
39 31 *
40   - * appId 在open.cnlive.com网站申请得到的appId
41   - * appKey 在open.cnlive.com网站申请得到的app_key
42 32 * channelId 直播视频Id
43 33 * authSuccess 初始化成功block
44 34 * authFailed 初始化失败block 回调一个errorInfo的字典
45 35 *
  36 + * result 获取主播状态 YES:获取状态成功
  37 + * NO:获取失败,不影响视频播放,但是获取不到主播离开、回来、直播结束等通知。可通过
  38 + * - (void)retryToGetAnchorStatusResult:(void(^)(BOOL result))result;方法重新获取
46 39 */
47   -- (instancetype)initLivePlayWithAppId:(NSString *)appId
48   - appKey:(NSString *)appKey
49   - channelId:(NSString *)channelId
50   - authSuccess:(void(^)(void))authSuccessBlock
51   - authFailed:(void(^)(NSDictionary *errorInfo))authFailedBlock;
  40 +- (instancetype)initLivePlayWithChannelId:(NSString *)channelId
  41 + authSuccess:(void(^)(void))authSuccessBlock
  42 + authFailed:(void(^)(NSDictionary *errorInfo))authFailedBlock
  43 + getAnchorStatusResult:(void(^)(BOOL result))result;
52 44  
53 45 /*
54 46 * 是否开启控制台输出日志(默认YES)
... ... @@ -73,12 +65,37 @@
73 65 */
74 66 - (void)retry;
75 67  
  68 +/* 重新获取主播直播状态
  69 + *
  70 + * result 重新获取主播直播状态,YES:成功 NO:失败
  71 + *
  72 + */
  73 +- (void)retryToGetAnchorStatusResult:(void(^)(BOOL result))result;
  74 +
  75 +/* 主播直播状态(只读)
  76 + *
  77 + */
  78 +@property (nonatomic, assign, readonly) CNLiveAnchorStatus anchorStatus;
  79 +
  80 +/*
  81 + * 主播直播状态改变通知
  82 + */
  83 +FOUNDATION_EXPORT NSString *const CNLiveAnchorStatusChangedNotification NS_AVAILABLE_IOS(7_0);
  84 +
76 85 #pragma mark - 普通播放器方法
77 86 /*
78 87 * 初始化播放器并设置播放地址
79 88 */
80 89 - (instancetype)initWithContentURL:(NSURL *)url;
81 90  
  91 +/* 解码方式(硬解/软解/自动)
  92 + *
  93 + * 建议系统版本高于8.0 选择硬解,或者自动选择解码方式,8.0以上的系统优先选择硬解
  94 + * 只在[prepareToPlay]调用前设置生效
  95 + *
  96 + */
  97 +@property(nonatomic) CNLiveMovieVideoDecoderMode videoDecoderMode;
  98 +
82 99 /* 重新启动拉流
83 100 *
84 101 * url 视频播放地址,该地址可以是本地地址或者服务器地址.如果为nil,则使用前一次播放地址
... ... @@ -86,6 +103,13 @@
86 103 */
87 104 - (void)reload:(NSURL *)aUrl;
88 105  
  106 +/**
  107 + * timeout指定拉流超时时间,单位是秒
  108 + * prepareTimeout 建立链接超时时间,默认值是10秒
  109 + * readTimeout 拉流超时时间,默认值是30秒
  110 + */
  111 +- (void)setTimeout:(int)prepareTimeout readTimeout:(int)readTimeout;
  112 +
89 113 /*
90 114 * 播放视频时是否需要自动播放,默认值为YES
91 115 */
... ... @@ -277,12 +301,4 @@ MP_EXTERN NSString * const MPMoviePlayerFirstAudioFrameRenderedNotification;
277 301 */
278 302 - (UIImage *)thumbnailImageAtCurrentTime;
279 303  
280   -/* 是否开启硬件解码
281   - *
282   - * 默认是关闭
283   - * 只在[prepareToPlay]调用前设置生效
284   - *
285   - */
286   -@property(nonatomic) BOOL shouldUseHWCodec;
287   -
288 304 @end
... ...
CNLivePlayerSDKTest/CNLivePlayerSDK.framework/Headers/CNLiveStreamerBase.h 0 → 100644
  1 +//
  2 +// CNLiveStreamerBase.h
  3 +// CNLivePlayerSDKDemo
  4 +//
  5 +// Created by iOS on 17/2/27.
  6 +// Copyright © 2017年 雷浩杰. All rights reserved.
  7 +//
  8 +
  9 +#import <Foundation/Foundation.h>
  10 +#import "CNLiveTypeDef.h"
  11 +#import <UIKit/UIKit.h>
  12 +
  13 +@interface CNLiveStreamerBase : NSObject
  14 +
  15 +/**
  16 + @abstract 视频帧率 默认:15
  17 + @discussion 当实际送入的视频帧率过高时会主动丢帧,有效范围[1~30]
  18 + */
  19 +@property (nonatomic, assign) int videoFPS;
  20 +
  21 +/**
  22 + @abstract 视频帧率最小值,默认与videoFPS相同
  23 + @discussion video frame per seconds 有效范围[1~30], 超出会提示参数错误
  24 + @discussion 不设置该值时表示网络自适应不使用动态帧率
  25 + */
  26 +@property (nonatomic, assign) int videoMinFPS;
  27 +
  28 +/**
  29 + @abstract 视频帧率最大值,默认与videoFPS相同
  30 + @discussion video frame per seconds 有效范围[1~30], 超出会提示参数错误
  31 + @discussion 不设置该值时表示网络自适应不使用动态帧率
  32 + */
  33 +@property (nonatomic, assign) int videoMaxFPS;
  34 +
  35 +/**
  36 + @abstract 视频编码器
  37 + @discussion video codec used for encode
  38 + */
  39 +@property (nonatomic, assign) CNLiveVideoCodec videoCodec;
  40 +
  41 +/**
  42 + @abstract 视频编码起始码率(单位:kbps)
  43 + @discussion 开始推流时的视频码率,开始推流后,根据网络情况在 [Min, Max]范围内调节
  44 + @discussion 视频码率上调则画面更清晰,下调则画面更模糊
  45 + */
  46 +@property (nonatomic, assign) int videoInitBitrate; // kbit/s of video
  47 +
  48 +/**
  49 + @abstract 视频编码最高码率(单位:kbps)
  50 + @discussion 视频码率自适应调整的上限, 为目标码率
  51 + */
  52 +@property (nonatomic, assign) int videoMaxBitrate; // kbit/s of video
  53 +
  54 +/**
  55 + @abstract 视频编码最低码率(单位:kbps)
  56 + @discussion 视频码率自适应调整的下限
  57 + */
  58 +@property (nonatomic, assign) int videoMinBitrate; // kbit/s of video
  59 +
  60 +/**
  61 + @abstract 最大关键帧间隔(单位:秒, 默认:3)
  62 + @discussion 即GOP长度 画面静止时,隔n秒插入一个关键帧
  63 + */
  64 +@property (nonatomic, assign) float maxKeyInterval; // seconds
  65 +
  66 +/**
  67 + @abstract 音频编码码率(单位:kbps)
  68 + @discussion 音频目标编码码率 (比如48,96,128等)
  69 + */
  70 +@property (nonatomic, assign) int audiokBPS; // kbit/s of audio
  71 +
  72 +/**
  73 + @abstract 查询当前是否处于推流状态 (建立连接中, 或连接中)
  74 + */
  75 +- (BOOL) isStreaming;
  76 +
  77 +/**
  78 + @abstract 静音推流 (仍然有音频输出发送, 只是音量为0)
  79 + @param bMute YES / ON
  80 + */
  81 +- (void)muteStream:(BOOL)bMute;
  82 +
  83 +/**
  84 + @abstract 截图功能,目前只支持jpg格式
  85 + @param jpegCompressionQuality 设置图像的压缩比例
  86 + @param filename 图片的文件名
  87 + */
  88 +- (void)takePhotoWithQuality:(CGFloat)jpegCompressionQuality
  89 + fileName:(NSString *)filename;
  90 +
  91 +@end
... ...
CNLivePlayerSDKTest/CNLivePlayerSDK.framework/Headers/CNLiveTypeDef.h
... ... @@ -46,6 +46,8 @@ typedef NS_ENUM(NSUInteger, CNLiveVideoCodec) {
46 46 CNLiveVideoCodec_QY265,
47 47 /// 视频编码器 - iOS VT264硬件编码器 (iOS 8.0以上支持)
48 48 CNLiveVideoCodec_VT264,
  49 + /// 视频编码器 - 由SDK自动选择( VT264 > X264)
  50 + CNLiveVideoCodec_AUTO = 100,
49 51 };
50 52  
51 53 #pragma mark - QYPublisher State
... ... @@ -94,7 +96,7 @@ typedef NS_ENUM(NSUInteger, CNLiveStreamState) {
94 96 typedef NS_ENUM(NSUInteger, CNLiveStreamErrorCode) {
95 97 /// 正常无错误
96 98 CNLiveStreamErrorCode_NONE = 0,
97   - /// SDK 鉴权失败 (暂时正常推流5~8分钟后终止推流)
  99 + /// (obsolete)
98 100 CNLiveStreamErrorCode_CNLiveAUTHFAILED,
99 101 /// 当前帧编码失败
100 102 CNLiveStreamErrorCode_ENCODE_FRAMES_FAILED,
... ... @@ -104,32 +106,96 @@ typedef NS_ENUM(NSUInteger, CNLiveStreamErrorCode) {
104 106 CNLiveStreamErrorCode_CONNECT_FAILED,
105 107 /// 网络连接中断
106 108 CNLiveStreamErrorCode_CONNECT_BREAK,
107   - /// rtmp 推流域名不存在
  109 + /// rtmp 推流域名不存在 (CNLive 自定义)
108 110 CNLiveStreamErrorCode_RTMP_NonExistDomain,
109   - /// rtmp 应用名不存在
  111 + /// rtmp 应用名不存在(CNLive 自定义)
110 112 CNLiveStreamErrorCode_RTMP_NonExistApplication,
111   - /// rtmp 流名已存在
  113 + /// rtmp 流名已存在(CNLive 自定义)
112 114 CNLiveStreamErrorCode_RTMP_AlreadyExistStreamName,
113   - /// rtmp 被黑名单拒绝
  115 + /// rtmp 被黑名单拒绝(CNLive 自定义)
114 116 CNLiveStreamErrorCode_RTMP_ForbiddenByBlacklist,
115   - /// rtmp 内部错误
  117 + /// rtmp 内部错误(CNLive 自定义)
116 118 CNLiveStreamErrorCode_RTMP_InternalError,
117   - /// rtmp URL 地址已过期
  119 + /// rtmp URL 地址已过期(CNLive 自定义)
118 120 CNLiveStreamErrorCode_RTMP_URLExpired,
119   - /// rtmp URL 地址签名错误
  121 + /// rtmp URL 地址签名错误(CNLive 自定义)
120 122 CNLiveStreamErrorCode_RTMP_SignatureDoesNotMatch,
121   - /// rtmp URL 中AccessKeyId非法
  123 + /// rtmp URL 中AccessKeyId非法(CNLive 自定义)
122 124 CNLiveStreamErrorCode_RTMP_InvalidAccessKeyId,
123   - /// rtmp URL 中参数错误
  125 + /// rtmp URL 中参数错误(CNLive 自定义)
124 126 CNLiveStreamErrorCode_RTMP_BadParams,
125   - /// rtmp URL 中的推流不在发布点内
  127 + /// rtmp URL 中的推流不在发布点内(CNLive 自定义)
126 128 CNLiveStreamErrorCode_RTMP_ForbiddenByRegion,
127   - /// SDK 因为鉴权失败停止推流
  129 + /// (obsolete)
128 130 CNLiveStreamErrorCode_FRAMES_THRESHOLD,
129   - /// 没有输入的数据,无法开始推流
  131 + /// (obsolete)
130 132 CNLiveStreamErrorCode_NO_INPUT_SAMPLE,
  133 + /// 对于URL中的域名解析失败
  134 + CNLiveStreamErrorCode_DNS_Parse_failed,
  135 + /// 对于URL对应的服务器连接失败(无法建立TCP连接)
  136 + CNLiveStreamErrorCode_Connect_Server_failed,
  137 + /// 跟RTMP服务器完成握手后,向{appname}/{streamname} 推流失败
  138 + CNLiveStreamErrorCode_RTMP_Publish_failed,
  139 + /// 音视频同步失败 (输入的音频和视频的时间戳的差值超过5s)
  140 + CNLiveStreamErrorCode_AV_SYNC_ERROR,
  141 + /// 非法地址(地址为空或url中的协议或本地文件的后缀SDK不支持, 请检查)
  142 + CNLiveStreamErrorCode_INVALID_ADDRESS,
131 143 /// 异常
132 144 CNLiveStreamErrorCode_ABNORMAL,
  145 +
  146 +};
  147 +
  148 +#pragma mark - 美颜
  149 +
  150 +typedef NS_ENUM(NSUInteger, CNLiveBeautyType) {
  151 + ///无
  152 + CNLiveBeautyTypeNone = 0,
  153 + ///旧美颜
  154 + CNLiveBeautyTypeOld,
  155 + ///红润美颜
  156 + CNLiveBeautyTypeRuddy,
  157 + ///美颜特效
  158 + CNLiveBeautyTypeSpecial
  159 +};
  160 +
  161 +typedef NS_ENUM(NSUInteger, CNLiveSpecialEffects) {
  162 + ///小清新
  163 + CNLiveSpecialEffectsFresh = 0,
  164 + ///靓丽
  165 + CNLiveSpecialEffectsPretty,
  166 + ///甜美可人
  167 + CNLiveSpecialEffectsSweet,
  168 + ///怀旧
  169 + CNLiveSpecialEffectsNostalgia,
  170 + ///蓝调
  171 + CNLiveSpecialEffectsBlues,
  172 + ///老照片
  173 + CNLiveSpecialEffectsOldPicture
  174 +};
  175 +
  176 +#pragma mark - player
  177 +/**
  178 + * 视频解码模式
  179 + */
  180 +typedef NS_ENUM(NSUInteger, CNLiveMovieVideoDecoderMode) {
  181 + ///视频解码方式采用软解
  182 + CNLiveMovieVideoDecoderMode_Software = 0,
  183 + ///视频解码方式采用硬解
  184 + CNLiveMovieVideoDecoderMode_Hardware,
  185 + ///自动选择解码方式,8.0以上的系统优先选择硬解
  186 + CNLiveMovieVideoDecoderMode_AUTO,
  187 +};
  188 +
  189 +/**
  190 + * 主播直播状态
  191 + */
  192 +typedef NS_ENUM(NSUInteger, CNLiveAnchorStatus) {
  193 + ///主播直播中
  194 + CNLiveAnchorStatusLiving = 0,
  195 + ///主播已离开
  196 + CNLiveAnchorStatusLeaving,
  197 + ///直播已结束
  198 + CNLiveAnchorStatusEnd,
133 199 };
134 200  
135 201 #endif /* CNLiveTypeDef_h */
... ...
CNLivePlayerSDKTest/CNLivePlayerSDK.framework/Headers/CNLiveWatermark.h 0 → 100644
  1 +//
  2 +// CNLiveWatermark.h
  3 +// CNLivePlayerSDKDemo
  4 +//
  5 +// Created by iOS on 17/2/27.
  6 +// Copyright © 2017年 雷浩杰. All rights reserved.
  7 +//
  8 +
  9 +#import <Foundation/Foundation.h>
  10 +#import <UIKit/UIKit.h>
  11 +
  12 +@interface CNLiveWatermark : NSObject
  13 +
  14 +/**
  15 + @abstract 水印logo的图片
  16 + @discussion 设置为nil为清除水印图片
  17 + @discussion 请注意背景图片的尺寸, 太大的图片会导致内存占用过高
  18 + @see
  19 + */
  20 +@property (nonatomic, readwrite) UIImage *logoPic;
  21 +
  22 +/**
  23 + @abstract 水印logo的图片(网络图片)
  24 + @discussion 设置为nil为清除水印图片
  25 + @discussion 请注意背景图片的尺寸, 太大的图片会导致内存占用过高
  26 + @see
  27 + */
  28 +@property (nonatomic, readwrite) NSURL *logoURL;
  29 +
  30 +/**
  31 + @abstract 水印logo的图片的位置和大小
  32 + @discussion 位置和大小的单位为预览视图的百分比, 左上角为(0,0), 右下角为(1.0, 1.0)
  33 + @discussion 如果宽为0, 则根据图像的宽高比, 和设置的高度比例, 计算得到宽度的比例
  34 + @discussion 如果高为0, 方法同上
  35 + */
  36 +@property (nonatomic, readwrite) CGRect logoRect;
  37 +
  38 +/**
  39 + @abstract 水印logo的图片的透明度
  40 + @discussion alpha为透明度(0-1),0完全透明,1完全不透明
  41 + */
  42 +@property (nonatomic, readwrite) CGFloat logoAlpha;
  43 +
  44 +/**
  45 + @abstract 水印文字的label
  46 + @discussion 借用UILabel来指定文字的颜色,字体, 透明度, 对齐方式等属性
  47 + @discussion 请注意保证背景图片的尺寸, 太大的图片会导致内存占用过高
  48 + @warning 如果使用非等宽字体, 可能导致闪烁(默认为Courier)
  49 + @warning picMixer和UILabel都有alpha属性, 建议只选用其中一个, 固定另一个为1.0,
  50 + 为了减少接口, 建议直接使用UILabel的属性,
  51 + 如果两者同时使用, 最终图层的alpha为两者乘积
  52 + */
  53 +@property (nonatomic, readwrite) UILabel *textLabel;
  54 +
  55 +/**
  56 + @abstract 水印文字的位置和大小
  57 + @discussion 位置和大小的单位为预览视图的百分比, 左上角为(0,0), 右下角为(1.0, 1.0)
  58 + @discussion 如果宽为0, 则根据文字图像的宽高比, 和设置的高度比例, 计算得到宽度的比例
  59 + @discussion 如果高为0, 方法同上
  60 + */
  61 +@property (nonatomic, readwrite) CGRect textRect;
  62 +
  63 +/**
  64 + @abstract 刷新水印文字的内容
  65 + @discussion 先修改文字的内容或格式,调用该方法后生效
  66 + */
  67 +- (void)updateTextLabel;
  68 +
  69 +@end
... ...
CNLivePlayerSDKTest/CNLivePlayerSDK.framework/Headers/CNLiveWebcastManager.h 0 → 100644
  1 +//
  2 +// CNLiveStreamManager.h
  3 +// CNLivePlayerSDKDemo
  4 +//
  5 +// Created by iOS on 17/2/23.
  6 +// Copyright © 2017年 雷浩杰. All rights reserved.
  7 +//
  8 +
  9 +#import <Foundation/Foundation.h>
  10 +#import "CNLiveTypeDef.h"
  11 +#import "CNLiveWatermark.h"
  12 +#import "CNLiveStreamerBase.h"
  13 +#import "CNLiveBeautifyFaceFilter.h"
  14 +#import "CNLiveAudioCapture.h"
  15 +#import <AVFoundation/AVFoundation.h>
  16 +#import <UIKit/UIKit.h>
  17 +
  18 +@interface CNLiveWebcastManager : NSObject
  19 +
  20 +/**
  21 + * 应用ID(只读)
  22 + */
  23 +@property (nonatomic, readonly) NSString *appId;
  24 +
  25 +/**
  26 + * 应用KEY(只读)
  27 + */
  28 +@property (nonatomic, readonly) NSString *appKey;
  29 +
  30 ++ (CNLiveWebcastManager *)manager;
  31 +
  32 +/**
  33 + @abstract 初始化直播云SDK
  34 + @param appId 在open.cnlive.com网站申请得到的appId
  35 + @param appKey 在open.cnlive.com网站申请得到的appKey
  36 + @warning 必传参数
  37 + */
  38 +- (void)initWithAppId:(NSString *)appId appKey:(NSString *)appKey;
  39 +
  40 +/**
  41 + @abstract 获取版本号
  42 + */
  43 ++ (NSString *)getVersion;
  44 +
  45 +@end
... ...
CNLivePlayerSDKTest/CNLivePlayerSDK.framework/Info.plist
No preview for this file type
CNLivePlayerSDKTest/CNLivePlayerSDKTest/Assets.xcassets/btn_dot.imageset/Contents.json 0 → 100644
  1 +{
  2 + "images" : [
  3 + {
  4 + "idiom" : "universal",
  5 + "filename" : "btn_dot.png",
  6 + "scale" : "1x"
  7 + },
  8 + {
  9 + "idiom" : "universal",
  10 + "scale" : "2x"
  11 + },
  12 + {
  13 + "idiom" : "universal",
  14 + "scale" : "3x"
  15 + }
  16 + ],
  17 + "info" : {
  18 + "version" : 1,
  19 + "author" : "xcode"
  20 + }
  21 +}
0 22 \ No newline at end of file
... ...
CNLivePlayerSDKTest/CNLivePlayerSDKTest/Assets.xcassets/btn_dot.imageset/btn_dot.png 0 → 100644

1.17 KB

CNLivePlayerSDKTest/CNLivePlayerSDKTest/Assets.xcassets/cancel.imageset/Contents.json 0 → 100644
  1 +{
  2 + "images" : [
  3 + {
  4 + "idiom" : "universal",
  5 + "filename" : "cancel.png",
  6 + "scale" : "1x"
  7 + },
  8 + {
  9 + "idiom" : "universal",
  10 + "scale" : "2x"
  11 + },
  12 + {
  13 + "idiom" : "universal",
  14 + "scale" : "3x"
  15 + }
  16 + ],
  17 + "info" : {
  18 + "version" : 1,
  19 + "author" : "xcode"
  20 + }
  21 +}
0 22 \ No newline at end of file
... ...
CNLivePlayerSDKTest/CNLivePlayerSDKTest/Assets.xcassets/cancel.imageset/cancel.png 0 → 100644

5.67 KB

CNLivePlayerSDKTest/CNLivePlayerSDKTest/Assets.xcassets/互动电视180x180.imageset/Contents.json 0 → 100644
  1 +{
  2 + "images" : [
  3 + {
  4 + "idiom" : "universal",
  5 + "filename" : "互动电视180x180.png",
  6 + "scale" : "1x"
  7 + },
  8 + {
  9 + "idiom" : "universal",
  10 + "scale" : "2x"
  11 + },
  12 + {
  13 + "idiom" : "universal",
  14 + "scale" : "3x"
  15 + }
  16 + ],
  17 + "info" : {
  18 + "version" : 1,
  19 + "author" : "xcode"
  20 + }
  21 +}
0 22 \ No newline at end of file
... ...
CNLivePlayerSDKTest/CNLivePlayerSDKTest/Assets.xcassets/互动电视180x180.imageset/互动电视180x180.png 0 → 100644

21.2 KB

CNLivePlayerSDKTest/CNLivePlayerSDKTest/Info.plist
... ... @@ -6,6 +6,10 @@
6 6 <string>en</string>
7 7 <key>CFBundleExecutable</key>
8 8 <string>$(EXECUTABLE_NAME)</string>
  9 + <key>CFBundleIcons</key>
  10 + <dict/>
  11 + <key>CFBundleIcons~ipad</key>
  12 + <dict/>
9 13 <key>CFBundleIdentifier</key>
10 14 <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
11 15 <key>CFBundleInfoDictionaryVersion</key>
... ...
CNLivePlayerSDKTest/CNLivePlayerSDKTest/Player/BackgroundView.h 0 → 100644
  1 +//
  2 +// BackgroundView.h
  3 +// CNLivePlayerSDKDemo
  4 +//
  5 +// Created by iOS on 17/3/9.
  6 +// Copyright © 2017年 雷浩杰. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +
  11 +@interface BackgroundView : UIView
  12 +
  13 +@property (nonatomic, assign) int anchorStatus; //设置主播状态
  14 +
  15 +
  16 +@end
... ...
CNLivePlayerSDKTest/CNLivePlayerSDKTest/Player/BackgroundView.m 0 → 100644
  1 +//
  2 +// BackgroundView.m
  3 +// CNLivePlayerSDKDemo
  4 +//
  5 +// Created by iOS on 17/3/9.
  6 +// Copyright © 2017年 雷浩杰. All rights reserved.
  7 +//
  8 +
  9 +#import "BackgroundView.h"
  10 +
  11 +@interface BackgroundView ()
  12 +
  13 +@property (nonatomic, strong) UILabel *anchorLab;
  14 +
  15 +@end
  16 +
  17 +
  18 +@implementation BackgroundView
  19 +
  20 +- (instancetype)initWithFrame:(CGRect)frame
  21 +{
  22 + self = [super initWithFrame:frame];
  23 + if (self) {
  24 + self.backgroundColor = [UIColor colorWithRed:54 green:54 blue:54 alpha:1];
  25 + [self addSubview:self.anchorLab];
  26 + }
  27 + return self;
  28 +}
  29 +
  30 +- (void)setAnchorStatus:(int)anchorStatus
  31 +{
  32 + switch (anchorStatus) {
  33 + case 0:
  34 + self.hidden = YES;
  35 + break;
  36 +
  37 + case 1:
  38 + _anchorLab.text = @"主播已离开,马上回来~";
  39 + self.hidden = NO;
  40 + break;
  41 +
  42 + case 2:
  43 + _anchorLab.text = @"直播已结束";
  44 + self.hidden = NO;
  45 + break;
  46 +
  47 + default:
  48 + break;
  49 + }
  50 +}
  51 +
  52 +#pragma mark -
  53 +#pragma mark - getter
  54 +
  55 +- (UILabel *)anchorLab
  56 +{
  57 + if (!_anchorLab) {
  58 + _anchorLab = [[UILabel alloc] initWithFrame:CGRectMake(0, self.bounds.size.height/2-25, self.bounds.size.width, 40)];
  59 + _anchorLab.textColor = [UIColor whiteColor];
  60 + _anchorLab.font = [UIFont systemFontOfSize:15];
  61 + _anchorLab.textAlignment = NSTextAlignmentCenter;
  62 + }
  63 + return _anchorLab;
  64 +}
  65 +
  66 +/*
  67 +// Only override drawRect: if you perform custom drawing.
  68 +// An empty implementation adversely affects performance during animation.
  69 +- (void)drawRect:(CGRect)rect {
  70 + // Drawing code
  71 +}
  72 +*/
  73 +
  74 +@end
... ...
CNLivePlayerSDKTest/CNLivePlayerSDKTest/Player/CNLiveViewController.h
... ... @@ -8,6 +8,16 @@
8 8  
9 9 #import <UIKit/UIKit.h>
10 10  
  11 +typedef NS_ENUM(NSInteger, PlayerType) {
  12 + PlayerTypeLiving = 0,
  13 + PlayerTypeVOD,
  14 + PlayerTypeNormal
  15 +};
  16 +
11 17 @interface CNLiveViewController : UIViewController
12 18  
  19 +@property (nonatomic, assign) PlayerType type;
  20 +@property (nonatomic, strong)NSString *videoUrlString;
  21 +
  22 +
13 23 @end
... ...
CNLivePlayerSDKTest/CNLivePlayerSDKTest/Player/CNLiveViewController.m
... ... @@ -8,18 +8,28 @@
8 8  
9 9 #import "CNLiveViewController.h"
10 10 #import <CNLivePlayerSDK/CNLiveMoviePlayerController.h>
  11 +#import <CNLivePlayerSDK/CNLiveWebcastManager.h>
  12 +#import "LoadingView.h"
  13 +#import "BackgroundView.h"
  14 +
  15 +#define KAppId @"60_irn9edco29"
  16 +#define KAppKey @"69fe70bda67e059286ad509d9f5377f815955645b52f94"
11 17  
12 18 @interface CNLiveViewController ()
13 19 {
14   - CNLiveMoviePlayerController *_player;
15   - UIButton *_playOrPauseBtn;
16   - UISlider *_timeSlide;
17   - UIProgressView *_bufferProgress;
18   - UILabel *_currentTimeLabel;
19   - UILabel *_durationLabel;
20 20 NSTimer *_currentTimer;
21 21 }
22 22  
  23 +@property (nonatomic, strong) LoadingView *loadingView;
  24 +@property (nonatomic, strong) UIButton *playOrPauseBtn;
  25 +@property (nonatomic, strong) UISlider *timeSlide;
  26 +@property (nonatomic, strong) UILabel *durationLabel;
  27 +@property (nonatomic, strong) UILabel *currentTimeLabel;
  28 +@property (nonatomic, strong) UIProgressView *bufferProgress;
  29 +@property (nonatomic, strong) UIButton *quitBtn;
  30 +@property (nonatomic, strong) BackgroundView *bgView;
  31 +@property (nonatomic, strong) UIView *toolBgView;
  32 +@property (nonatomic, strong) CNLiveMoviePlayerController *player;
23 33 @end
24 34  
25 35 @implementation CNLiveViewController
... ... @@ -35,87 +45,70 @@
35 45 //添加播放器通知
36 46 [self installMovieNotificationObservers];
37 47  
38   - //获取SDK版本号
39   - NSLog(@">>>>>>>>>>>>%@", [CNLiveMoviePlayerController getVersion]);
40   -
41   - //测试vId
42   - //a9c5f9a2d6114bf98f2aff89a55d4f98
43   - //0e12b70817c440509d88f67d4e975fe0
44   - //点播播放
45   - _player = [[CNLiveMoviePlayerController alloc] initVodPlayWithAppId:@"60_irg1rhs308"
46   - appKey:@"4e7a37b27a717a9e9b0a7aea4620ee55ea61fbf923bf46"
47   - vId:@"20161126"
48   - authSuccess:^{
49   -
50   - _player.shouldUseHWCodec = YES;
51   - _player.view.frame = CGRectMake(0, 20, self.view.frame.size.width, self.view.frame.size.width*9/16);
52   - _player.shouldAutoplay = YES;
53   - [_player prepareToPlay];
54   - [self.view addSubview:_player.view];
55   -
56   - } authFailed:^(NSDictionary *errorInfo) {
57   - NSLog(@"初始化点播播放器失败%@", errorInfo);
58   - }];
59   -
60   - //直播播放
61   -// _player = [[CNLiveMoviePlayerController alloc] initLivePlayWithAppId:@"60_irg1rhs308"
62   -// appKey:@"4e7a37b27a717a9e9b0a7aea4620ee55ea61fbf923bf46"
63   -// channelId:@"news"
64   -// authSuccess:^{
65   -//
66   -// _player.shouldUseHWCodec = YES;
67   -// _player.view.frame = CGRectMake(0, 20, self.view.frame.size.width, self.view.frame.size.width*9/16);
68   -// _player.shouldAutoplay = YES;
69   -// [_player prepareToPlay];
70   -// [self.view addSubview:_player.view];
71   -//
72   -// } authFailed:^(NSDictionary *errorInfo) {
73   -// NSLog(@"初始化直播播放器失败:%@", errorInfo);
74   -// }];
75   -
76   - _playOrPauseBtn = [UIButton buttonWithType:UIButtonTypeSystem];
77   - _playOrPauseBtn.frame = CGRectMake(10, self.view.frame.size.width*9/16+20+50, 50, 50);
78   - [_playOrPauseBtn setImage:[UIImage imageNamed:@"play"] forState:UIControlStateNormal];
79   - [_playOrPauseBtn addTarget:self action:@selector(playOrPauseBtnAction) forControlEvents:UIControlEventTouchUpInside];
80   - [self.view addSubview:_playOrPauseBtn];
81 48  
82   - _currentTimeLabel = [[UILabel alloc] initWithFrame:CGRectMake(70, self.view.frame.size.width*9/16+20+50, 60, 50)];
83   - _currentTimeLabel.textColor = [UIColor blackColor];
84   - _currentTimeLabel.font = [UIFont systemFontOfSize:13];
85   - [_currentTimeLabel setText:[NSString stringWithFormat:@"00:00:00"]];
86   - [self.view addSubview:_currentTimeLabel];
  49 + [[CNLiveWebcastManager manager] initWithAppId:KAppId appKey:KAppKey];
87 50  
88   - _bufferProgress = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
89   - _bufferProgress.frame = CGRectMake(130+2, self.view.frame.size.width*9/16+20+50+24, self.view.frame.size.width-130-80-4, 1);
90   - _bufferProgress.trackTintColor = [UIColor darkGrayColor];
91   - _bufferProgress.progressTintColor = [UIColor blackColor];
92   - _bufferProgress.progress = 0;
93   - [self.view addSubview:_bufferProgress];
94   -
95   - _timeSlide = [[UISlider alloc] initWithFrame:CGRectMake(130, self.view.frame.size.width*9/16+20+50, self.view.frame.size.width-130-80, 50)];
96   - [_timeSlide setMinimumTrackTintColor:[UIColor redColor]];
97   - [_timeSlide setMaximumTrackTintColor:[UIColor clearColor]];
98   - [_timeSlide addTarget:self action:@selector(beginScrubbing) forControlEvents:UIControlEventTouchDown];
99   - [_timeSlide addTarget:self action:@selector(endScrubbing) forControlEvents:UIControlEventTouchUpInside];
100   - [_timeSlide addTarget:self action:@selector(endScrubbing) forControlEvents:UIControlEventTouchUpOutside];
101   - [self.view addSubview:_timeSlide];
  51 + if (_type == PlayerTypeLiving) {
  52 + //直播播放
  53 + _player = [[CNLiveMoviePlayerController alloc] initLivePlayWithChannelId:@"iOStest"
  54 + authSuccess:^{
  55 +
  56 + _player.videoDecoderMode = CNLiveMovieVideoDecoderMode_AUTO;
  57 + _player.view.frame = self.view.bounds;
  58 + _player.shouldAutoplay = YES;
  59 + [_player prepareToPlay];
  60 + [self.view addSubview:_player.view];
  61 + [self.view sendSubviewToBack:_player.view];
  62 +
  63 + } authFailed:^(NSDictionary *errorInfo) {
  64 + NSLog(@"初始化直播播放器失败:%@", errorInfo);
  65 + [_loadingView stopLoading];
  66 +
  67 + } getAnchorStatusResult:^(BOOL result) {
  68 +
  69 + NSLog(@"-------------获取主播状态%d", result ? YES : NO);
  70 +
  71 + }];
  72 +
  73 + } else if (_type == PlayerTypeVOD) {
  74 +
  75 + //点播播放
  76 + _player = [[CNLiveMoviePlayerController alloc] initVodPlayWithVId:@"aaa123"
  77 + authSuccess:^{
  78 +
  79 + _player.videoDecoderMode = CNLiveMovieVideoDecoderMode_AUTO;
  80 + _player.view.frame = self.view.bounds;
  81 + _player.shouldAutoplay = YES;
  82 + [_player prepareToPlay];
  83 + [self.view addSubview:_player.view];
  84 + [self.view sendSubviewToBack:_player.view];
  85 +
  86 + } authFailed:^(NSDictionary *errorInfo) {
  87 + NSLog(@"初始化点播播放器失败%@", errorInfo);
  88 + }];
  89 +
  90 + } else {
  91 +
  92 + //普通播放
  93 + _player = [[CNLiveMoviePlayerController alloc] initWithContentURL:[NSURL URLWithString:_videoUrlString]];
  94 + _player.videoDecoderMode = CNLiveMovieVideoDecoderMode_AUTO;
  95 + _player.view.frame = self.view.bounds;
  96 + _player.shouldAutoplay = YES;
  97 + [_player prepareToPlay];
  98 + [self.view addSubview:_player.view];
  99 + [self.view sendSubviewToBack:_player.view];
  100 + }
102 101  
103   - _durationLabel = [[UILabel alloc] initWithFrame:CGRectMake(self.view.frame.size.width-60-10, self.view.frame.size.width*9/16+20+50, 60, 50)];
104   - _durationLabel.textColor = [UIColor blackColor];
105   - _durationLabel.font = [UIFont systemFontOfSize:13];
106   - [_durationLabel setText:[NSString stringWithFormat:@"00:00:00"]];
107   - [self.view addSubview:_durationLabel];
  102 + [self.view addSubview:self.bgView];
  103 + [self.view addSubview:self.loadingView];
  104 + [self.view addSubview:self.quitBtn];
  105 + [self.view addSubview:self.toolBgView];
  106 + [self.toolBgView addSubview:self.playOrPauseBtn];
  107 + [self.toolBgView addSubview:self.currentTimeLabel];
  108 + [self.toolBgView addSubview:self.bufferProgress];
  109 + [self.toolBgView addSubview:self.timeSlide];
  110 + [self.toolBgView addSubview:self.durationLabel];
108 111  
109   - UIButton *exitBtn = [UIButton buttonWithType:UIButtonTypeCustom];
110   - exitBtn.frame = CGRectMake((CGRectGetWidth(self.view.frame)-80)/2, 400, 80, 30);
111   - [exitBtn setTitle:@"退出" forState:UIControlStateNormal];
112   - [exitBtn setTitleColor:[UIColor colorWithRed:23/255.0 green:110/255.0 blue:254/255.0 alpha:1] forState:UIControlStateNormal];
113   - [exitBtn addTarget:self action:@selector(exitBtnAction) forControlEvents:UIControlEventTouchUpInside];
114   - exitBtn.layer.cornerRadius = 5;
115   - exitBtn.layer.masksToBounds = YES;
116   - exitBtn.layer.borderColor = [UIColor blackColor].CGColor;
117   - exitBtn.layer.borderWidth = 1;
118   - [self.view addSubview:exitBtn];
119 112 }
120 113  
121 114 - (void)exitBtnAction
... ... @@ -136,6 +129,8 @@
136 129 }
137 130 }
138 131  
  132 +#pragma mark -
  133 +#pragma mark - action
139 134 - (void)playOrPauseBtnAction
140 135 {
141 136 if (_player.isPlaying) {
... ... @@ -145,6 +140,18 @@
145 140 }
146 141 }
147 142  
  143 +- (void)retryBtnAction
  144 +{
  145 + _loadingView.retryBtn.hidden = YES;
  146 + [_loadingView startLoading];
  147 +
  148 + if (_player.isPlaying) {
  149 + [self getAnchorStatusRetryBtnAction];
  150 + } else {
  151 + [_player reload:nil];
  152 + }
  153 +}
  154 +
148 155 - (void)beginScrubbing //currentSlide
149 156 {
150 157 [_player pause];
... ... @@ -156,6 +163,41 @@
156 163 [_player play];
157 164 }
158 165  
  166 +
  167 +- (void)timeChange
  168 +{
  169 + _bufferProgress.progress = _player.playableDuration/_player.duration;
  170 + if (!_player.isPreparedToPlay) {
  171 + return;
  172 + }
  173 +
  174 + _timeSlide.value = _player.currentPlaybackTime;
  175 + _timeSlide.maximumValue = _player.duration;
  176 +
  177 + NSInteger currentSeconds = (NSInteger)_player.currentPlaybackTime;
  178 + NSInteger seconds = currentSeconds % 60;
  179 + NSInteger minutes = currentSeconds / 60;
  180 + NSInteger hours = minutes / 60;
  181 +
  182 + NSInteger durationall = (NSInteger)_player.duration;
  183 + NSInteger durationSeconds = durationall % 60;
  184 + NSInteger durationMinutes = durationall / 60;
  185 + NSInteger durationHours = durationMinutes / 60;
  186 +
  187 + _currentTimeLabel.text = [NSString stringWithFormat:@"%02ld:%02ld:%02ld", (long)hours, (long)minutes%60, (long)seconds];
  188 + _durationLabel.text = [NSString stringWithFormat:@"%02ld:%02ld:%02ld", (long)durationHours, (long)durationMinutes%60, (long)durationSeconds];
  189 +}
  190 +
  191 +//重新获取主播连接状态
  192 +- (void)getAnchorStatusRetryBtnAction
  193 +{
  194 + [_player retryToGetAnchorStatusResult:^(BOOL result) {
  195 + _loadingView.retryBtn.hidden = result;
  196 + }];
  197 +}
  198 +
  199 +#pragma mark -
  200 +#pragma mark - addObservers
159 201 -(void)installMovieNotificationObservers //添加视频播放通知
160 202 {
161 203 //视频加载状态改变
... ... @@ -181,45 +223,45 @@
181 223 selector:@selector(moviePlayBackStateDidChange:)
182 224 name:MPMoviePlayerPlaybackStateDidChangeNotification
183 225 object:nil];
  226 +
  227 + if (_type != PlayerTypeLiving) return;
  228 +
  229 + //获取主播状态通知(点播和普通播放不需要注册该通知)
  230 + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(anchorStatusChanged:)
  231 + name:CNLiveAnchorStatusChangedNotification
  232 + object:nil];
  233 +
184 234 }
185 235  
186 236 - (void)removeMovieNotificationObservers
187 237 {
188   - [[NSNotificationCenter defaultCenter]removeObserver:self name:MPMoviePlayerLoadStateDidChangeNotification object:nil];
189   - [[NSNotificationCenter defaultCenter]removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
190   - [[NSNotificationCenter defaultCenter]removeObserver:self name:MPMediaPlaybackIsPreparedToPlayDidChangeNotification object:nil];
191   - [[NSNotificationCenter defaultCenter]removeObserver:self name:MPMoviePlayerPlaybackStateDidChangeNotification object:nil];
192   -}
193   -
194   -- (void)timeChange
195   -{
196   - _bufferProgress.progress = _player.playableDuration/_player.duration;
197   - if (!_player.isPreparedToPlay) {
198   - return;
199   - }
  238 + [[NSNotificationCenter defaultCenter]removeObserver:self
  239 + name:MPMoviePlayerLoadStateDidChangeNotification
  240 + object:nil];
  241 + [[NSNotificationCenter defaultCenter]removeObserver:self
  242 + name:MPMoviePlayerPlaybackDidFinishNotification
  243 + object:nil];
  244 + [[NSNotificationCenter defaultCenter]removeObserver:self
  245 + name:MPMediaPlaybackIsPreparedToPlayDidChangeNotification
  246 + object:nil];
  247 + [[NSNotificationCenter defaultCenter]removeObserver:self
  248 + name:MPMoviePlayerPlaybackStateDidChangeNotification
  249 + object:nil];
  250 + if (_type != PlayerTypeLiving) return;
200 251  
201   - _timeSlide.value = _player.currentPlaybackTime;
202   - _timeSlide.maximumValue = _player.duration;
203   -
204   - NSInteger currentSeconds = (NSInteger)_player.currentPlaybackTime;
205   - NSInteger seconds = currentSeconds % 60;
206   - NSInteger minutes = currentSeconds / 60;
207   - NSInteger hours = minutes / 60;
208   -
209   - NSInteger durationall = (NSInteger)_player.duration;
210   - NSInteger durationSeconds = durationall % 60;
211   - NSInteger durationMinutes = durationall / 60;
212   - NSInteger durationHours = durationMinutes / 60;
213   -
214   - _currentTimeLabel.text = [NSString stringWithFormat:@"%02ld:%02ld:%02ld", (long)hours, (long)minutes%60, (long)seconds];
215   - _durationLabel.text = [NSString stringWithFormat:@"%02ld:%02ld:%02ld", (long)durationHours, (long)durationMinutes%60, (long)durationSeconds];
  252 + [[NSNotificationCenter defaultCenter]removeObserver:self
  253 + name:CNLiveAnchorStatusChangedNotification
  254 + object:nil];
216 255 }
217 256  
  257 +#pragma mark -
  258 +#pragma mark - notification
218 259 - (void)loadStateDidChange:(NSNotification *)notification
219 260 {
220 261 if (_player) {
221 262 MPMovieLoadState loadState = _player.loadState;
222 263 if ((loadState & MPMovieLoadStatePlaythroughOK) != 0) {
  264 + [_loadingView stopLoading];
223 265 NSLog(@"loadStateDidChange: MPMovieLoadStatePlaythroughOK: %d\n", (int)loadState);
224 266  
225 267 } else if ((loadState & MPMovieLoadStateStalled) != 0) {
... ... @@ -235,6 +277,13 @@
235 277 {
236 278 if (_player) {
237 279 int reason = [[[notification userInfo] valueForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey] intValue];
  280 + if (MPMovieFinishReasonPlaybackError == reason) {
  281 + _loadingView.retryBtn.hidden = NO;
  282 + [_loadingView stopLoading];
  283 + } else {
  284 + _loadingView.retryBtn.hidden = YES;
  285 + }
  286 +
238 287 switch (reason)
239 288 {
240 289 case MPMovieFinishReasonPlaybackEnded:
... ... @@ -302,6 +351,124 @@
302 351 }
303 352 }
304 353  
  354 +
  355 +- (void)anchorStatusChanged:(NSNotification *)notification
  356 +{
  357 + if (_player.anchorStatus == 2) {
  358 + [self.loadingView removeFromSuperview];
  359 + [self.loadingView stopLoading];
  360 + }
  361 +
  362 + _bgView.anchorStatus = _player.anchorStatus;
  363 +}
  364 +
  365 +
  366 +- (void)anchorStatusConnectFailed
  367 +{ //重新连接获取主播状态
  368 + _loadingView.retryBtn.hidden = NO;
  369 +}
  370 +
  371 +#pragma mark -
  372 +#pragma mark - gatter
  373 +- (LoadingView *)loadingView
  374 +{
  375 + if (!_loadingView) {
  376 + _loadingView = [[LoadingView alloc] initWithFrame:CGRectMake(0, 0, 70, 70)];
  377 + _loadingView.center = self.view.center;
  378 + [_loadingView.retryBtn addTarget:self action:@selector(retryBtnAction) forControlEvents:UIControlEventTouchUpInside];
  379 + }
  380 + return _loadingView;
  381 +}
  382 +
  383 +- (UIButton *)playOrPauseBtn
  384 +{
  385 + if (!_playOrPauseBtn) {
  386 + _playOrPauseBtn = [UIButton buttonWithType:UIButtonTypeCustom];
  387 + _playOrPauseBtn.frame = CGRectMake(15, 10, 40, 40);
  388 + [_playOrPauseBtn setImage:[UIImage imageNamed:@"play"] forState:UIControlStateNormal];
  389 + [_playOrPauseBtn addTarget:self action:@selector(playOrPauseBtnAction) forControlEvents:UIControlEventTouchUpInside];
  390 + }
  391 + return _playOrPauseBtn;
  392 +}
  393 +
  394 +- (UIButton *)quitBtn
  395 +{
  396 + if (!_quitBtn) {
  397 + _quitBtn = [UIButton buttonWithType:UIButtonTypeCustom];
  398 + _quitBtn.frame = CGRectMake(self.view.bounds.size.width-50, 25, 30, 30);
  399 + [_quitBtn setImage:[UIImage imageNamed:@"cancel"] forState:UIControlStateNormal];
  400 + [_quitBtn addTarget:self action:@selector(exitBtnAction) forControlEvents:UIControlEventTouchUpInside];
  401 + }
  402 + return _quitBtn;
  403 +}
  404 +
  405 +- (UISlider *)timeSlide
  406 +{
  407 + if (!_timeSlide) {
  408 + _timeSlide = [[UISlider alloc] initWithFrame:CGRectMake(130, 15, self.view.frame.size.width-130-80, 30)];
  409 + [_timeSlide setThumbImage:[UIImage imageNamed:@"btn_dot"] forState:UIControlStateNormal];
  410 + [_timeSlide setMinimumTrackTintColor:[UIColor redColor]];
  411 + [_timeSlide setMaximumTrackTintColor:[UIColor clearColor]];
  412 + [_timeSlide addTarget:self action:@selector(beginScrubbing) forControlEvents:UIControlEventTouchDown];
  413 + [_timeSlide addTarget:self action:@selector(endScrubbing) forControlEvents:UIControlEventTouchUpInside];
  414 + [_timeSlide addTarget:self action:@selector(endScrubbing) forControlEvents:UIControlEventTouchUpOutside];
  415 + }
  416 + return _timeSlide;
  417 +}
  418 +
  419 +- (UILabel *)currentTimeLabel
  420 +{
  421 + if (!_currentTimeLabel) {
  422 + _currentTimeLabel = [[UILabel alloc] initWithFrame:CGRectMake(65, 5, 60, 50)];
  423 + _currentTimeLabel.textColor = [UIColor whiteColor];
  424 + _currentTimeLabel.font = [UIFont systemFontOfSize:13];
  425 + [_currentTimeLabel setText:[NSString stringWithFormat:@"00:00:00"]];
  426 + }
  427 + return _currentTimeLabel;
  428 +}
  429 +
  430 +- (UILabel *)durationLabel
  431 +{
  432 + if (!_durationLabel) {
  433 + _durationLabel = [[UILabel alloc] initWithFrame:CGRectMake(self.view.frame.size.width-60-10, 5, 60, 50)];
  434 + _durationLabel.textColor = [UIColor whiteColor];
  435 + _durationLabel.font = [UIFont systemFontOfSize:13];
  436 + [_durationLabel setText:[NSString stringWithFormat:@"00:00:00"]];
  437 + }
  438 + return _durationLabel;
  439 +}
  440 +
  441 +- (UIProgressView *)bufferProgress
  442 +{
  443 + if (!_bufferProgress) {
  444 + _bufferProgress = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
  445 + _bufferProgress.frame = CGRectMake(130+2, 29, self.view.frame.size.width-130-80-4, 1);
  446 + _bufferProgress.trackTintColor = [UIColor darkGrayColor];
  447 + _bufferProgress.progressTintColor = [UIColor lightGrayColor];
  448 + _bufferProgress.progress = 0;
  449 + }
  450 + return _bufferProgress;
  451 +}
  452 +
  453 +- (BackgroundView *)bgView
  454 +{
  455 + if (!_bgView) {
  456 + _bgView = [[BackgroundView alloc] initWithFrame:self.view.bounds];
  457 + _bgView.hidden = YES;
  458 + }
  459 + return _bgView;
  460 +}
  461 +
  462 +- (UIView *)toolBgView
  463 +{
  464 + if (!_toolBgView) {
  465 + _toolBgView = [[UIView alloc] initWithFrame:CGRectMake(0, self.view.bounds.size.height-60, self.view.bounds.size.width, 60)];
  466 + _toolBgView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5];
  467 + }
  468 + return _toolBgView;
  469 +}
  470 +
  471 +
305 472 - (void)didReceiveMemoryWarning {
306 473 [super didReceiveMemoryWarning];
307 474 // Dispose of any resources that can be recreated.
... ...
CNLivePlayerSDKTest/CNLivePlayerSDKTest/Player/LoadingView.h 0 → 100644
  1 +//
  2 +// LoadingView.h
  3 +// CNLivePlayerSDKDemo
  4 +//
  5 +// Created by iOS on 17/3/8.
  6 +// Copyright © 2017年 雷浩杰. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +
  11 +@interface LoadingView : UIView
  12 +
  13 +@property (nonatomic, strong) UIButton *retryBtn;
  14 +
  15 +- (void)startLoading;
  16 +
  17 +- (void)stopLoading;
  18 +
  19 +@end
... ...
CNLivePlayerSDKTest/CNLivePlayerSDKTest/Player/LoadingView.m 0 → 100644
  1 +//
  2 +// LoadingView.m
  3 +// CNLivePlayerSDKDemo
  4 +//
  5 +// Created by iOS on 17/3/8.
  6 +// Copyright © 2017年 雷浩杰. All rights reserved.
  7 +//
  8 +
  9 +#import "LoadingView.h"
  10 +
  11 +@interface LoadingView ()
  12 +
  13 +@property (nonatomic, strong) UIActivityIndicatorView *activityIndicator;
  14 +
  15 +@end
  16 +
  17 +@implementation LoadingView
  18 +
  19 +- (instancetype)initWithFrame:(CGRect)frame
  20 +{
  21 + self = [super initWithFrame:frame];
  22 + if (self) {
  23 + [self addSubview:self.activityIndicator];
  24 + [self addSubview:self.retryBtn];
  25 + [self.activityIndicator startAnimating];
  26 +
  27 + }
  28 + return self;
  29 +}
  30 +
  31 +- (void)startLoading
  32 +{
  33 + [_activityIndicator startAnimating];
  34 +}
  35 +
  36 +- (void)stopLoading
  37 +{
  38 + dispatch_async(dispatch_get_main_queue(), ^{
  39 + [self.activityIndicator stopAnimating];
  40 + });
  41 +}
  42 +
  43 +#pragma mark -
  44 +#pragma mark - getter
  45 +- (UIActivityIndicatorView *)activityIndicator
  46 +{
  47 + if (!_activityIndicator) {
  48 + _activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
  49 + _activityIndicator.center = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2);
  50 + }
  51 + return _activityIndicator;
  52 +}
  53 +
  54 +- (UIButton *)retryBtn
  55 +{
  56 + if (!_retryBtn) {
  57 + _retryBtn = [UIButton buttonWithType:UIButtonTypeCustom];
  58 + _retryBtn.frame = CGRectMake(self.bounds.size.width/2-30, self.bounds.size.height/2-20, 60, 40);
  59 + [_retryBtn setTitle:@"重试" forState:UIControlStateNormal];
  60 + [_retryBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
  61 + _retryBtn.hidden = YES;
  62 + _retryBtn.layer.cornerRadius = 10;
  63 + _retryBtn.layer.masksToBounds = YES;
  64 + _retryBtn.layer.borderColor = [UIColor blackColor].CGColor;
  65 + _retryBtn.layer.borderWidth = 1;
  66 +
  67 + }
  68 + return _retryBtn;
  69 +}
  70 +
  71 +@end
... ...
CNLivePlayerSDKTest/CNLivePlayerSDKTest/Player/NormalViewController.h deleted 100644 → 0
1   -//
2   -// NormalViewController.h
3   -// CNLivePlayerSDKTest
4   -//
5   -// Created by 雷浩杰 on 16/8/10.
6   -// Copyright © 2016年 雷浩杰. All rights reserved.
7   -//
8   -
9   -#import <UIKit/UIKit.h>
10   -
11   -@interface NormalViewController : UIViewController
12   -
13   -@property (nonatomic, strong)NSString *videoUrlString;
14   -
15   -@end
CNLivePlayerSDKTest/CNLivePlayerSDKTest/Player/NormalViewController.m deleted 100644 → 0
1   -//
2   -// NormalViewController.m
3   -// CNLivePlayerSDKTest
4   -//
5   -// Created by 雷浩杰 on 16/8/10.
6   -// Copyright © 2016年 雷浩杰. All rights reserved.
7   -//
8   -
9   -#import "NormalViewController.h"
10   -#import <CNLivePlayerSDK/CNLiveMoviePlayerController.h>
11   -
12   -@interface NormalViewController ()
13   -{
14   - CNLiveMoviePlayerController *_player;
15   - UIButton *_playOrPauseBtn;
16   - UISlider *_timeSlide;
17   - UIProgressView *_bufferProgress;
18   - UILabel *_currentTimeLabel;
19   - UILabel *_durationLabel;
20   - NSTimer *_currentTimer;
21   -}
22   -
23   -@end
24   -
25   -@implementation NormalViewController
26   -
27   -- (void)viewDidLoad {
28   - [super viewDidLoad];
29   - self.view.backgroundColor = [UIColor grayColor];
30   -
31   - _currentTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(timeChange) userInfo:nil repeats:YES];
32   -
33   - [self installMovieNotificationObservers];
34   -
35   - _player = [[CNLiveMoviePlayerController alloc] initWithContentURL:[NSURL URLWithString:_videoUrlString]];
36   - _player.shouldUseHWCodec = YES;
37   - _player.view.frame = CGRectMake(0, 20, self.view.frame.size.width, self.view.frame.size.width*9/16);
38   - _player.shouldAutoplay = YES;
39   - [_player prepareToPlay];
40   - [self.view addSubview:_player.view];
41   -
42   - _playOrPauseBtn = [UIButton buttonWithType:UIButtonTypeSystem];
43   - _playOrPauseBtn.frame = CGRectMake(10, self.view.frame.size.width*9/16+20+50, 50, 50);
44   - [_playOrPauseBtn setImage:[UIImage imageNamed:@"play"] forState:UIControlStateNormal];
45   - [_playOrPauseBtn addTarget:self action:@selector(playOrPauseBtnAction) forControlEvents:UIControlEventTouchUpInside];
46   - [self.view addSubview:_playOrPauseBtn];
47   -
48   - _currentTimeLabel = [[UILabel alloc] initWithFrame:CGRectMake(70, self.view.frame.size.width*9/16+20+50, 60, 50)];
49   - _currentTimeLabel.textColor = [UIColor blackColor];
50   - _currentTimeLabel.font = [UIFont systemFontOfSize:13];
51   - [_currentTimeLabel setText:[NSString stringWithFormat:@"00:00:00"]];
52   - [self.view addSubview:_currentTimeLabel];
53   -
54   - _bufferProgress = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
55   - _bufferProgress.frame = CGRectMake(130+2, self.view.frame.size.width*9/16+20+50+24, self.view.frame.size.width-130-80-4, 1);
56   - _bufferProgress.trackTintColor = [UIColor darkGrayColor];
57   - _bufferProgress.progressTintColor = [UIColor blackColor];
58   - _bufferProgress.progress = 0;
59   - [self.view addSubview:_bufferProgress];
60   -
61   - _timeSlide = [[UISlider alloc] initWithFrame:CGRectMake(130, self.view.frame.size.width*9/16+20+50, self.view.frame.size.width-130-80, 50)];
62   - [_timeSlide setMinimumTrackTintColor:[UIColor redColor]];
63   - [_timeSlide setMaximumTrackTintColor:[UIColor clearColor]];
64   - [_timeSlide addTarget:self action:@selector(beginScrubbing) forControlEvents:UIControlEventTouchDown];
65   - [_timeSlide addTarget:self action:@selector(endScrubbing) forControlEvents:UIControlEventTouchUpInside];
66   - [_timeSlide addTarget:self action:@selector(endScrubbing) forControlEvents:UIControlEventTouchUpOutside];
67   - [self.view addSubview:_timeSlide];
68   -
69   - _durationLabel = [[UILabel alloc] initWithFrame:CGRectMake(self.view.frame.size.width-60-10, self.view.frame.size.width*9/16+20+50, 60, 50)];
70   - _durationLabel.textColor = [UIColor blackColor];
71   - _durationLabel.font = [UIFont systemFontOfSize:13];
72   - [_durationLabel setText:[NSString stringWithFormat:@"00:00:00"]];
73   - [self.view addSubview:_durationLabel];
74   -
75   - UIButton *exitBtn = [UIButton buttonWithType:UIButtonTypeCustom];
76   - exitBtn.frame = CGRectMake((CGRectGetWidth(self.view.frame)-80)/2, 400, 80, 30);
77   - [exitBtn setTitle:@"退出" forState:UIControlStateNormal];
78   - [exitBtn setTitleColor:[UIColor colorWithRed:23/255.0 green:110/255.0 blue:254/255.0 alpha:1] forState:UIControlStateNormal];
79   - [exitBtn addTarget:self action:@selector(exitBtnAction) forControlEvents:UIControlEventTouchUpInside];
80   - exitBtn.layer.cornerRadius = 5;
81   - exitBtn.layer.masksToBounds = YES;
82   - exitBtn.layer.borderColor = [UIColor blackColor].CGColor;
83   - exitBtn.layer.borderWidth = 1;
84   - [self.view addSubview:exitBtn];
85   -}
86   -
87   -- (void)exitBtnAction
88   -{
89   - [_player stop];
90   - [_currentTimer invalidate];
91   - _currentTimer = nil;
92   - [self removeMovieNotificationObservers];
93   - [self dismissViewControllerAnimated:YES completion:NULL];
94   -}
95   -
96   -- (void)changePlayBtnStatus:(BOOL)playing
97   -{
98   - if (playing) {
99   - [_playOrPauseBtn setImage:[UIImage imageNamed:@"pause"] forState:UIControlStateNormal];
100   - } else {
101   - [_playOrPauseBtn setImage:[UIImage imageNamed:@"play"] forState:UIControlStateNormal];
102   - }
103   -}
104   -
105   -- (void)playOrPauseBtnAction
106   -{
107   - if (_player.isPlaying) {
108   - [_player pause];
109   - } else {
110   - [_player play];
111   - }
112   -}
113   -
114   -- (void)beginScrubbing //currentSlide
115   -{
116   - [_player pause];
117   -}
118   -
119   -- (void)endScrubbing //currentSlide
120   -{
121   - [_player setCurrentPlaybackTime:_timeSlide.value];
122   - [_player play];
123   -}
124   -
125   --(void)installMovieNotificationObservers //添加视频播放通知
126   -{
127   - [[NSNotificationCenter defaultCenter] addObserver:self
128   - selector:@selector(loadStateDidChange:)
129   - name:MPMoviePlayerLoadStateDidChangeNotification
130   - object:nil];
131   -
132   - [[NSNotificationCenter defaultCenter] addObserver:self
133   - selector:@selector(moviePlayBackDidFinish:)
134   - name:MPMoviePlayerPlaybackDidFinishNotification
135   - object:nil];
136   -
137   - [[NSNotificationCenter defaultCenter] addObserver:self
138   - selector:@selector(mediaIsPreparedToPlayDidChange:)
139   - name:MPMediaPlaybackIsPreparedToPlayDidChangeNotification
140   - object:nil];
141   -
142   - [[NSNotificationCenter defaultCenter] addObserver:self
143   - selector:@selector(moviePlayBackStateDidChange:)
144   - name:MPMoviePlayerPlaybackStateDidChangeNotification
145   - object:nil];
146   -}
147   -
148   -- (void)removeMovieNotificationObservers
149   -{
150   - [[NSNotificationCenter defaultCenter]removeObserver:self name:MPMoviePlayerLoadStateDidChangeNotification object:nil];
151   - [[NSNotificationCenter defaultCenter]removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
152   - [[NSNotificationCenter defaultCenter]removeObserver:self name:MPMediaPlaybackIsPreparedToPlayDidChangeNotification object:nil];
153   - [[NSNotificationCenter defaultCenter]removeObserver:self name:MPMoviePlayerPlaybackStateDidChangeNotification object:nil];
154   -}
155   -
156   -- (void)timeChange
157   -{
158   - _bufferProgress.progress = _player.playableDuration/_player.duration;
159   - if (!_player.isPreparedToPlay) {
160   - return;
161   - }
162   -
163   - _timeSlide.value = _player.currentPlaybackTime;
164   - _timeSlide.maximumValue = _player.duration;
165   -
166   - NSInteger currentSeconds = (NSInteger)_player.currentPlaybackTime;
167   - NSInteger seconds = currentSeconds % 60;
168   - NSInteger minutes = currentSeconds / 60;
169   - NSInteger hours = minutes / 60;
170   -
171   - NSInteger durationall = (NSInteger)_player.duration;
172   - NSInteger durationSeconds = durationall % 60;
173   - NSInteger durationMinutes = durationall / 60;
174   - NSInteger durationHours = durationMinutes / 60;
175   -
176   - _currentTimeLabel.text = [NSString stringWithFormat:@"%02ld:%02ld:%02ld", (long)hours, (long)minutes%60, (long)seconds];
177   - _durationLabel.text = [NSString stringWithFormat:@"%02ld:%02ld:%02ld", (long)durationHours, (long)durationMinutes%60, (long)durationSeconds];
178   -}
179   -
180   -- (void)loadStateDidChange:(NSNotification *)notification
181   -{
182   - if (_player) {
183   - MPMovieLoadState loadState = _player.loadState;
184   - if ((loadState & MPMovieLoadStatePlaythroughOK) != 0) {
185   - NSLog(@"loadStateDidChange: MPMovieLoadStatePlaythroughOK: %d\n", (int)loadState);
186   -
187   - } else if ((loadState & MPMovieLoadStateStalled) != 0) {
188   - NSLog(@"loadStateDidChange: MPMovieLoadStateStalled: %d\n", (int)loadState);
189   -
190   - } else {
191   - NSLog(@"loadStateDidChange: ???: %d\n", (int)loadState);
192   - }
193   - }
194   -}
195   -
196   -- (void)moviePlayBackDidFinish:(NSNotification *)notification
197   -{
198   - if (_player) {
199   - int reason = [[[notification userInfo] valueForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey] intValue];
200   - switch (reason)
201   - {
202   - case MPMovieFinishReasonPlaybackEnded:
203   - NSLog(@"playbackStateDidChange: MPMovieFinishReasonPlaybackEnded: %d\n", reason);
204   - break;
205   -
206   - case MPMovieFinishReasonUserExited:
207   - NSLog(@"playbackStateDidChange: MPMovieFinishReasonUserExited: %d\n", reason);
208   - break;
209   -
210   - case MPMovieFinishReasonPlaybackError:
211   - NSLog(@"playbackStateDidChange: MPMovieFinishReasonPlaybackError: %d\n", reason);
212   - break;
213   -
214   - default:
215   - NSLog(@"playbackPlayBackDidFinish: ???: %d\n", reason);
216   - break;
217   - }
218   - }
219   -}
220   -
221   -- (void)mediaIsPreparedToPlayDidChange:(NSNotification *)notification
222   -{
223   - if (_player) {
224   - NSLog(@"isPreparedToPlay");
225   - }
226   -}
227   -
228   -- (void)moviePlayBackStateDidChange:(NSNotification *)notification
229   -{
230   - if (_player) {
231   -
232   - switch (_player.playbackState) {
233   - case MPMoviePlaybackStateStopped: {
234   - [self changePlayBtnStatus:NO];
235   - NSLog(@"moviePlayBackStateDidChange : MPMoviePlaybackStateStopped");
236   - break;
237   - }
238   - case MPMoviePlaybackStatePlaying: {
239   - [self changePlayBtnStatus:YES];
240   - NSLog(@"moviePlayBackStateDidChange : MPMoviePlaybackStatePlaying");
241   - break;
242   - }
243   - case MPMoviePlaybackStatePaused:
244   - [self changePlayBtnStatus:NO];
245   - NSLog(@"moviePlayBackStateDidChange : MPMoviePlaybackStatePaused");
246   - break;
247   - case MPMoviePlaybackStateInterrupted:
248   - [self changePlayBtnStatus:NO];
249   - NSLog(@"moviePlayBackStateDidChange : MPMoviePlaybackStateInterrupted");
250   - break;
251   - case MPMoviePlaybackStateSeekingForward:
252   - [self changePlayBtnStatus:NO];
253   - NSLog(@"moviePlayBackStateDidChange : MPMoviePlaybackStateSeekingForward");
254   - break;
255   - case MPMoviePlaybackStateSeekingBackward:
256   - [self changePlayBtnStatus:NO];
257   - NSLog(@"moviePlayBackStateDidChange : MPMoviePlaybackStateSeekingBackward");
258   - break;
259   - default:
260   - [self changePlayBtnStatus:NO];
261   - NSLog(@"moviePlayBackStateDidChange : %ld", _player.playbackState);
262   - break;
263   - }
264   - }
265   -}
266   -
267   -- (void)didReceiveMemoryWarning {
268   - [super didReceiveMemoryWarning];
269   - // Dispose of any resources that can be recreated.
270   -}
271   -
272   -/*
273   -#pragma mark - Navigation
274   -
275   -// In a storyboard-based application, you will often want to do a little preparation before navigation
276   -- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
277   - // Get the new view controller using [segue destinationViewController].
278   - // Pass the selected object to the new view controller.
279   -}
280   -*/
281   -
282   -@end
CNLivePlayerSDKTest/CNLivePlayerSDKTest/Player/PlayerViewController.m
... ... @@ -8,7 +8,6 @@
8 8  
9 9 #import "PlayerViewController.h"
10 10 #import "CNLiveViewController.h"
11   -#import "NormalViewController.h"
12 11  
13 12 @interface PlayerViewController ()<UITextFieldDelegate, UITableViewDelegate, UITableViewDataSource>
14 13 {
... ... @@ -25,34 +24,29 @@
25 24  
26 25 self.view.backgroundColor = [UIColor whiteColor];
27 26  
28   - UIButton *cnlivePlayerBtn = [UIButton buttonWithType:UIButtonTypeCustom];
29   - cnlivePlayerBtn.frame = CGRectMake((CGRectGetWidth(self.view.frame)-150)/2, 50, 150, 50);
30   - [cnlivePlayerBtn setTitle:@"视讯云内容播放" forState:UIControlStateNormal];
31   - [cnlivePlayerBtn setTitleColor:[UIColor colorWithRed:23/255.0 green:110/255.0 blue:254/255.0 alpha:1] forState:UIControlStateNormal];
32   - [cnlivePlayerBtn addTarget:self action:@selector(cnlivePlayerBtnAction) forControlEvents:UIControlEventTouchUpInside];
33   - cnlivePlayerBtn.layer.cornerRadius = 10;
34   - cnlivePlayerBtn.layer.masksToBounds = YES;
35   - cnlivePlayerBtn.layer.borderColor = [UIColor blackColor].CGColor;
36   - cnlivePlayerBtn.layer.borderWidth = 1;
37   - [self.view addSubview:cnlivePlayerBtn];
  27 + NSArray *titlesArr = @[@"视讯云直播播放",@"视讯云点播播放",@"普通播放"];
  28 +
  29 + for (int i = 0; i < 3; i ++) {
  30 + UIButton *cnlivePlayerBtn = [UIButton buttonWithType:UIButtonTypeCustom];
  31 + cnlivePlayerBtn.frame = CGRectMake((CGRectGetWidth(self.view.frame)-150)/2, 80+i*(40+20), 150, 40);
  32 + [cnlivePlayerBtn setTitle:titlesArr[i] forState:UIControlStateNormal];
  33 + [cnlivePlayerBtn setTitleColor:[UIColor colorWithRed:23/255.0 green:110/255.0 blue:254/255.0 alpha:1] forState:UIControlStateNormal];
  34 + [cnlivePlayerBtn addTarget:self action:@selector(cnlivePlayerBtnAction:) forControlEvents:UIControlEventTouchUpInside];
  35 + cnlivePlayerBtn.tag = 10000+i;
  36 + cnlivePlayerBtn.layer.cornerRadius = 10;
  37 + cnlivePlayerBtn.layer.masksToBounds = YES;
  38 + cnlivePlayerBtn.layer.borderColor = [UIColor blackColor].CGColor;
  39 + cnlivePlayerBtn.layer.borderWidth = 1;
  40 + [self.view addSubview:cnlivePlayerBtn];
  41 + }
38 42  
39   - UIButton *normalPlayerBtn = [UIButton buttonWithType:UIButtonTypeCustom];
40   - normalPlayerBtn.frame = CGRectMake((CGRectGetWidth(self.view.frame)-150)/2, 130, 150, 50);
41   - [normalPlayerBtn setTitle:@"普通播放" forState:UIControlStateNormal];
42   - [normalPlayerBtn setTitleColor:[UIColor colorWithRed:23/255.0 green:110/255.0 blue:254/255.0 alpha:1] forState:UIControlStateNormal];
43   - [normalPlayerBtn addTarget:self action:@selector(normalPlayerBtnAction) forControlEvents:UIControlEventTouchUpInside];
44   - normalPlayerBtn.layer.cornerRadius = 10;
45   - normalPlayerBtn.layer.masksToBounds = YES;
46   - normalPlayerBtn.layer.borderColor = [UIColor blackColor].CGColor;
47   - normalPlayerBtn.layer.borderWidth = 1;
48   - [self.view addSubview:normalPlayerBtn];
49 43  
50   - UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, 200, 80, 30)];
  44 + UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, 260, 80, 30)];
51 45 label.text = @"播放地址:";
52 46 label.font = [UIFont systemFontOfSize:15];
53 47 [self.view addSubview:label];
54 48  
55   - _textField = [[UITextField alloc] initWithFrame:CGRectMake(90, 200, self.view.frame.size.width-100, 30)];
  49 + _textField = [[UITextField alloc] initWithFrame:CGRectMake(90, 260, self.view.frame.size.width-100, 30)];
56 50 _textField.delegate = self;
57 51 [self.view addSubview:_textField];
58 52 _textField.borderStyle = UITextBorderStyleRoundedRect;
... ... @@ -66,13 +60,13 @@
66 60 _textField.text = @"http://video00.cnlive.com/video/data1/2015/0518/cnlive_200.mp4";
67 61 }
68 62  
69   - _historyTableView = [[UITableView alloc] initWithFrame:CGRectMake(10, 240, self.view.frame.size.width, [UIScreen mainScreen].bounds.size.height-80-240) style:UITableViewStylePlain];
  63 + _historyTableView = [[UITableView alloc] initWithFrame:CGRectMake(10, 300, self.view.frame.size.width, [UIScreen mainScreen].bounds.size.height-80-300) style:UITableViewStylePlain];
70 64 _historyTableView.delegate = self;
71 65 _historyTableView.dataSource = self;
72 66 [self.view addSubview:_historyTableView];
73 67  
74 68 UIButton *exitBtn = [UIButton buttonWithType:UIButtonTypeCustom];
75   - exitBtn.frame = CGRectMake((CGRectGetWidth(self.view.frame)-150)/2, [UIScreen mainScreen].bounds.size.height-70, 150, 50);
  69 + exitBtn.frame = CGRectMake((CGRectGetWidth(self.view.frame)-150)/2, [UIScreen mainScreen].bounds.size.height-70, 150, 40);
76 70 [exitBtn setTitle:@"退出" forState:UIControlStateNormal];
77 71 [exitBtn setTitleColor:[UIColor colorWithRed:23/255.0 green:110/255.0 blue:254/255.0 alpha:1] forState:UIControlStateNormal];
78 72 [exitBtn addTarget:self action:@selector(exitBtnAction) forControlEvents:UIControlEventTouchUpInside];
... ... @@ -88,10 +82,16 @@
88 82 [self dismissViewControllerAnimated:YES completion:NULL];
89 83 }
90 84  
91   -- (void)cnlivePlayerBtnAction
  85 +- (void)cnlivePlayerBtnAction:(UIButton *)button
92 86 {
93   - CNLiveViewController *cnlive = [[CNLiveViewController alloc] init];
94   - [self presentViewController:cnlive animated:YES completion:NULL];
  87 + if (button.tag == 10002) {
  88 + [self normalPlayerBtnAction];
  89 + } else {
  90 + CNLiveViewController *cnlive = [[CNLiveViewController alloc] init];
  91 + cnlive.type = (PlayerType)button.tag-10000;
  92 + [self presentViewController:cnlive animated:YES completion:NULL];
  93 + }
  94 +
95 95 }
96 96  
97 97 - (void)normalPlayerBtnAction
... ... @@ -117,7 +117,8 @@
117 117 [_historyTableView reloadData];
118 118 }
119 119  
120   - NormalViewController *cnlive = [[NormalViewController alloc] init];
  120 + CNLiveViewController *cnlive = [[CNLiveViewController alloc] init];
  121 + cnlive.type = PlayerTypeNormal;
121 122 cnlive.videoUrlString = _textField.text;
122 123 [self presentViewController:cnlive animated:YES completion:NULL];
123 124 }
... ... @@ -163,13 +164,13 @@
163 164 }
164 165  
165 166 /*
166   -#pragma mark - Navigation
167   -
168   -// In a storyboard-based application, you will often want to do a little preparation before navigation
169   -- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
170   - // Get the new view controller using [segue destinationViewController].
171   - // Pass the selected object to the new view controller.
172   -}
173   -*/
  167 + #pragma mark - Navigation
  168 +
  169 + // In a storyboard-based application, you will often want to do a little preparation before navigation
  170 + - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
  171 + // Get the new view controller using [segue destinationViewController].
  172 + // Pass the selected object to the new view controller.
  173 + }
  174 + */
174 175  
175 176 @end
... ...
CNLivePlayerSDKTest/CNLivePlayerSDKTest/Streamer/FilterFunctionView.h 0 → 100644
  1 +//
  2 +// FilterFunctionView.h
  3 +// CNLivePlayerSDKDemo
  4 +//
  5 +// Created by iOS on 16/12/21.
  6 +// Copyright © 2016年 雷浩杰. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +
  11 +typedef void(^FilterViewBlock)(float grindRatio , float whitenRatio, float intensity);
  12 +
  13 +typedef void(^FilterCurrentType)(NSInteger currentType);
  14 +
  15 +typedef void(^FilterCurrentIdx)(NSInteger currentIdx);
  16 +
  17 +@interface FilterFunctionView : UIView
  18 +
  19 +@property (nonatomic, copy) FilterViewBlock filterViewBlock;
  20 +
  21 +@property (nonatomic, copy) FilterCurrentType currentTypeBlock;
  22 +
  23 +@property (nonatomic, copy) FilterCurrentIdx currentIdxBlock;
  24 +
  25 +@end
  26 +
... ...
CNLivePlayerSDKTest/CNLivePlayerSDKTest/Streamer/FilterFunctionView.m 0 → 100644
  1 +//
  2 +// FilterFunctionView.m
  3 +// CNLivePlayerSDKDemo
  4 +//
  5 +// Created by iOS on 16/12/21.
  6 +// Copyright © 2016年 雷浩杰. All rights reserved.
  7 +//
  8 +
  9 +#import "FilterFunctionView.h"
  10 +#import "SliderView.h"
  11 +
  12 +@interface FilterFunctionView ()<SliderViewDelegate,UIPickerViewDelegate,UIPickerViewDataSource>
  13 +{
  14 + NSArray *_dataArr;
  15 +}
  16 +
  17 +@property (nonatomic, strong) SliderView *slider1;
  18 +@property (nonatomic, strong) SliderView *slider2;
  19 +@property (nonatomic, strong) SliderView *slider3;
  20 +@property (nonatomic, strong) UISegmentedControl * filterGroupType;
  21 +@property (nonatomic, strong) UIPickerView *effectPicker;
  22 +
  23 +@end
  24 +
  25 +@implementation FilterFunctionView
  26 +
  27 +- (instancetype)initWithFrame:(CGRect)frame
  28 +{
  29 + self = [super initWithFrame:frame];
  30 + if (self) {
  31 + [self addSubview:self.slider1];
  32 + [self addSubview:self.slider2];
  33 + [self addSubview:self.slider3];
  34 + [self addSubview:self.effectPicker];
  35 + [self addSubview:self.filterGroupType];
  36 +
  37 + _dataArr = @[@"小清新",@"靓丽",@"甜美可人",@"怀旧",@"蓝调",@"老照片"];
  38 +
  39 + }
  40 + return self;
  41 +}
  42 +
  43 +#pragma mark -
  44 +#pragma mark - SliderViewDelegate
  45 +
  46 +- (void)sliderValueChenged
  47 +{
  48 + if (_filterViewBlock) {
  49 + _filterViewBlock(_slider1.currentValue, _slider2.currentValue, _slider3.currentValue);
  50 + }
  51 +}
  52 +
  53 +- (void)onSegCtrl:(UISegmentedControl *)sender
  54 +{
  55 +
  56 + if (sender.selectedSegmentIndex == 0) {
  57 + _slider1.hidden = YES;
  58 + _slider2.hidden = YES;
  59 + _slider3.hidden = YES;
  60 + _effectPicker.hidden = YES;
  61 +
  62 + } else if (sender.selectedSegmentIndex == 1) {
  63 + _slider1.hidden = NO;
  64 + _slider2.hidden = YES;
  65 + _slider3.hidden = YES;
  66 + _effectPicker.hidden = YES;
  67 + } else if (sender.selectedSegmentIndex == 2) {
  68 + _slider1.hidden = NO;
  69 + _slider2.hidden = NO;
  70 + _slider3.hidden = NO;
  71 + _effectPicker.hidden = YES;
  72 + } else {
  73 + _slider1.hidden = NO;
  74 + _slider2.hidden = NO;
  75 + _slider3.hidden = NO;
  76 + _effectPicker.hidden = NO;
  77 + }
  78 +
  79 + _currentTypeBlock ? _currentTypeBlock(sender.selectedSegmentIndex) : nil;
  80 +
  81 +}
  82 +
  83 +#pragma mark -
  84 +#pragma mark - effectPicker
  85 +- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
  86 +{
  87 + return 1;
  88 +}
  89 +
  90 +- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
  91 +{
  92 + return _dataArr.count;
  93 +}
  94 +
  95 +- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
  96 +{
  97 + return _dataArr[row];
  98 +}
  99 +
  100 +- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
  101 +{
  102 + _currentIdxBlock ? _currentIdxBlock(row) : nil;
  103 +}
  104 +
  105 +#pragma mark -
  106 +#pragma mark - getter
  107 +
  108 +- (SliderView *)slider1
  109 +{
  110 + if (!_slider1) {
  111 + _slider1 = [[SliderView alloc] initWithFrame:CGRectMake(8, 50, self.bounds.size.width-16, 24) title:@"磨皮"];
  112 + _slider1.delagate = self;
  113 + }
  114 + return _slider1;
  115 +}
  116 +
  117 +- (SliderView *)slider2
  118 +{
  119 + if (!_slider2) {
  120 + _slider2 = [[SliderView alloc] initWithFrame:CGRectMake(8, 80, self.bounds.size.width-16, 24) title:@"美白"];
  121 + _slider2.delagate = self;
  122 + }
  123 + return _slider2;
  124 +}
  125 +
  126 +- (SliderView *)slider3
  127 +{
  128 + if (!_slider3) {
  129 + _slider3 = [[SliderView alloc] initWithFrame:CGRectMake(8, 110, self.bounds.size.width-16, 24) title:@"特效"];
  130 + _slider3.delagate = self;
  131 + }
  132 + return _slider3;
  133 +}
  134 +
  135 +- (UIPickerView *)effectPicker
  136 +{
  137 + if (!_effectPicker) {
  138 + _effectPicker = [[UIPickerView alloc] initWithFrame:CGRectMake(8, 130, self.bounds.size.width-16, 100)];
  139 + _effectPicker.showsSelectionIndicator=YES;
  140 + _effectPicker.tintColor = [UIColor whiteColor];
  141 + _effectPicker.dataSource = self;
  142 + _effectPicker.delegate = self;
  143 + _effectPicker.hidden = YES;
  144 + }
  145 + return _effectPicker;
  146 +}
  147 +
  148 +- (UISegmentedControl *)filterGroupType
  149 +{
  150 + if (!_filterGroupType) {
  151 + NSArray *items = @[ @"关",
  152 + @"旧美颜",
  153 + @"红润美颜",
  154 + @"美颜特效",
  155 + ];
  156 +
  157 + _filterGroupType = [[UISegmentedControl alloc] initWithItems:items];
  158 + _filterGroupType.frame = CGRectMake(10, 0, self.bounds.size.width-20, 30);
  159 + _filterGroupType.tintColor= [UIColor blackColor];
  160 + _filterGroupType.selectedSegmentIndex = 0;
  161 + _filterGroupType.layer.cornerRadius = 5;
  162 + _filterGroupType.selectedSegmentIndex = 1;
  163 + [_filterGroupType addTarget:self action:@selector(onSegCtrl:) forControlEvents:UIControlEventValueChanged];
  164 + }
  165 + return _filterGroupType;
  166 +}
  167 +@end
... ...
CNLivePlayerSDKTest/CNLivePlayerSDKTest/Streamer/SliderView.h 0 → 100644
  1 +//
  2 +// SliderView.h
  3 +// CNLivePlayerSDKDemo
  4 +//
  5 +// Created by iOS on 16/12/21.
  6 +// Copyright © 2016年 雷浩杰. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +
  11 +@protocol SliderViewDelegate <NSObject>
  12 +
  13 +- (void)sliderValueChenged;
  14 +
  15 +@end
  16 +
  17 +@interface SliderView : UIView
  18 +
  19 +@property (nonatomic, strong) UILabel* nameL; // 滑块对应参数名称
  20 +@property (nonatomic, strong) UISlider* slider; // 滑块
  21 +@property (nonatomic, strong) UILabel* valueL; // 滑块当前的值
  22 +@property (nonatomic, assign, readonly) float currentValue;
  23 +@property (nonatomic, assign) id<SliderViewDelegate> delagate;
  24 +
  25 +- (instancetype)initWithFrame:(CGRect)frame title:(NSString *)title;
  26 +
  27 +@end
... ...
CNLivePlayerSDKTest/CNLivePlayerSDKTest/Streamer/SliderView.m 0 → 100644
  1 +//
  2 +// SliderView.m
  3 +// CNLivePlayerSDKDemo
  4 +//
  5 +// Created by iOS on 16/12/21.
  6 +// Copyright © 2016年 雷浩杰. All rights reserved.
  7 +//
  8 +
  9 +#import "SliderView.h"
  10 +
  11 +@implementation SliderView
  12 +{
  13 + NSString *_title;
  14 +}
  15 +
  16 +- (instancetype)initWithFrame:(CGRect)frame title:(NSString *)title{
  17 + self = [super initWithFrame:frame];
  18 + if (self) {
  19 + _title = title;
  20 + [self addSubview:self.nameL];
  21 + [self addSubview:self.valueL];
  22 + [self addSubview:self.slider];
  23 + }
  24 + return self;
  25 +}
  26 +
  27 +- (float)currentValue
  28 +{
  29 + return _slider.value;
  30 +}
  31 +
  32 +#pragma mark -
  33 +#pragma mark - action
  34 +
  35 +- (void)onSlider:(UISlider *)slider
  36 +{
  37 + _valueL.text = [NSString stringWithFormat:@"%d",(int)(slider.value * 100)];
  38 + if (self.delagate && [self.delagate respondsToSelector:@selector(sliderValueChenged)]) {
  39 + [self.delagate sliderValueChenged];
  40 + }
  41 +}
  42 +
  43 +#pragma mark -
  44 +#pragma mark - getter
  45 +
  46 +- (UILabel *)nameL
  47 +{
  48 + if (!_nameL) {
  49 + _nameL = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 40, 24)];
  50 + _nameL.text = _title;
  51 + _nameL.textAlignment = NSTextAlignmentCenter;
  52 + _nameL.textColor = [UIColor whiteColor];
  53 + _nameL.backgroundColor = [UIColor colorWithRed:192/255.0 green:192/255.0 blue:192/255.0 alpha:1];
  54 + _nameL.layer.cornerRadius = 5;
  55 + _nameL.layer.masksToBounds = YES;
  56 + }
  57 + return _nameL;
  58 +}
  59 +
  60 +- (UILabel *)valueL
  61 +{
  62 + if (!_valueL) {
  63 + _valueL = [[UILabel alloc] initWithFrame:CGRectMake(self.bounds.size.width-40, 0, 40, 24)];
  64 + _valueL.text = @"50";
  65 + _valueL.textAlignment = NSTextAlignmentCenter;
  66 + _valueL.textColor = [UIColor whiteColor];
  67 + _valueL.backgroundColor = [UIColor colorWithRed:192/255.0 green:192/255.0 blue:192/255.0 alpha:1];
  68 + _valueL.layer.cornerRadius = 5;
  69 + _valueL.layer.masksToBounds = YES;
  70 +
  71 + }
  72 + return _valueL;
  73 +}
  74 +
  75 +- (UISlider *)slider
  76 +{
  77 + if (!_slider) {
  78 + _slider = [[UISlider alloc] initWithFrame:CGRectMake(40, 0, self.bounds.size.width-80, 24)];
  79 + _slider.value = 0.5;
  80 + [_slider addTarget:self action:@selector(onSlider:) forControlEvents:UIControlEventValueChanged];
  81 + }
  82 + return _slider;
  83 +}
  84 +@end
... ...
CNLivePlayerSDKTest/CNLivePlayerSDKTest/Streamer/StreamerDetailViewController.m
... ... @@ -8,44 +8,70 @@
8 8  
9 9 #import "StreamerDetailViewController.h"
10 10 #import <CNLivePlayerSDK/CNLiveGPUStreamerKit.h>
11   -#import "CommonCrypto/CommonDigest.h"
  11 +#import <CNLivePlayerSDK/CNLiveWebcastManager.h>
  12 +#import "FilterFunctionView.h"
12 13  
13 14 #define Width [UIScreen mainScreen].bounds.size.width
14 15 #define Height [UIScreen mainScreen].bounds.size.height
15 16  
16   -#define kAPPID @"60_irg1rhs308"
17   -#define kAPPKEY @"4e7a37b27a717a9e9b0a7aea4620ee55ea61fbf923bf46"
18   -
  17 +#define KAppId @"60_irn9edco29"
  18 +#define KAppKey @"69fe70bda67e059286ad509d9f5377f815955645b52f94"
  19 +#define KBundleId @"com.cnlive.video"
19 20  
20 21 @interface StreamerDetailViewController ()<UIGestureRecognizerDelegate>
21 22 {
22   - UILabel *_stateLab;
23 23 UIButton *_startLiveBtn;
24   -
25   - NSString *_activityId; //用于查询活动状态
  24 + CGFloat _currentPinchZoomFactor;//当前触摸缩放因子
26 25 }
27 26  
28 27 @property (nonatomic,strong) UIView *captureView;
  28 +@property (nonatomic,strong) UILabel *stateLab;
29 29 @property (nonatomic,strong) NSURL *hostURL;
30   -
  30 +@property (nonatomic,strong) FilterFunctionView *filterView;
31 31 @property (nonatomic,strong) CNLiveGPUStreamerKit *kitCN; //直播推流
32 32  
33 33 @end
34 34  
35 35 @implementation StreamerDetailViewController
36 36  
  37 +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
  38 +{
  39 + if (_kitCN) {
  40 + return UIInterfaceOrientationMaskAllButUpsideDown;
  41 + } else {
  42 + return UIInterfaceOrientationMaskPortrait;
  43 + }
  44 +}
  45 +
  46 +-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
  47 +
  48 + UIInterfaceOrientation orie = [[UIApplication sharedApplication] statusBarOrientation];
  49 + [_kitCN rotatePreviewTo:orie];
  50 +
  51 + if (_kitCN.streamerBase.isStreaming) {
  52 + [_kitCN rotateStreamTo:orie];
  53 + }
  54 +
  55 + [UIView animateWithDuration:0.2 animations:^{
  56 + _captureView.frame = self.view.bounds;
  57 + _stateLab.frame = CGRectMake(0, Height-100, Width, 100);
  58 + }];
  59 +}
  60 +
37 61 - (void)viewDidLoad {
38 62 [super viewDidLoad];
39 63  
40 64 [self.view addSubview:self.captureView];
  65 + [self.view addSubview:self.filterView];
  66 + [self.view addSubview:self.stateLab];
41 67  
42 68 if (_isAuthLive) {
43 69  
44 70 NSString *activityId = [NSString stringWithFormat:@"%d%d%d%d%d",arc4random()%9,arc4random()%9,arc4random()%9,arc4random()%9,arc4random()%9];
  71 +
  72 + [[CNLiveWebcastManager manager] initWithAppId:KAppId appKey:KAppKey];
45 73  
46   - _activityId = activityId;
47   -
48   - _kitCN = [[CNLiveGPUStreamerKit alloc] initWithDefaultConfigWithAppId:kAPPID appKey:kAPPKEY activityId:activityId channelId:@"test001" isHorizontalScreen:@"0"];
  74 + _kitCN = [[CNLiveGPUStreamerKit alloc] initWithDefaultConfigWithActivityId:activityId channelId:@"iOStest" isHorizontalScreen:@"0"];
49 75  
50 76 // _kitCN.activityName = @"iOS test";
51 77 // _kitCN.coverImgUrl = @"djfiwooa";
... ... @@ -68,38 +94,18 @@
68 94 [_startLiveBtn setTitle:@"停止直播" forState:UIControlStateSelected];
69 95  
70 96 [self addButton:@"关闭预览" frame:CGRectMake(10, 40, 80, 40) action:@selector(startPreview:)];
71   -
72 97 [self addButton:@"退出" frame:CGRectMake(190, 40, 80, 40) action:@selector(quit)];
73   -
74 98 [self addButton:@"美颜" frame:CGRectMake(10, 100, 80, 40) action:@selector(openFilter:)];
75   -
76 99 [self addButton:@"摄像头" frame:CGRectMake(100, 100, 80, 40) action:@selector(changeCamera:)];
77   -
78 100 [self addButton:@"闪光灯" frame:CGRectMake(190, 100, 80, 40) action:@selector(openFlash)];
79 101  
80   - _stateLab = [[UILabel alloc] initWithFrame:CGRectMake(0, 160, Width, 200)];
81   - _stateLab.backgroundColor = [UIColor clearColor];
82   - _stateLab.numberOfLines = 0;
83   - _stateLab.textColor = [UIColor redColor];
84   - [self.view addSubview:_stateLab];
85 102  
86 103 UITapGestureRecognizer * singleRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTap:)];
87 104 singleRecognizer.delegate = self;
88 105 [self.captureView addGestureRecognizer:singleRecognizer];
89 106  
90   -}
91   -
92   -- (void)addObservers
93   -{
94   - [[NSNotificationCenter defaultCenter] addObserver:self
95   - selector:@selector(captureStateChange)
96   - name:CNLiveCaptureStateDidChangeNotification
97   - object:nil];
98   -
99   - [[NSNotificationCenter defaultCenter] addObserver:self
100   - selector:@selector(streamStateChange)
101   - name:CNLiveStreamStateDidChangeNotification
102   - object:nil];
  107 + UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(pinchDetected:)];
  108 + [self.view addGestureRecognizer:pinch];
103 109  
104 110 }
105 111  
... ... @@ -110,7 +116,6 @@
110 116 button = [UIButton buttonWithType:UIButtonTypeCustom];
111 117 button.frame = frame;
112 118 [button setTitle: title forState: UIControlStateNormal];
113   - button.backgroundColor = [UIColor lightGrayColor];
114 119 [button addTarget:self action:action forControlEvents:UIControlEventTouchUpInside];
115 120 button.titleLabel.font = [UIFont systemFontOfSize:15];
116 121 [button setTitleColor:[UIColor colorWithRed:23/255.0 green:110/255.0 blue:254/255.0 alpha:1] forState:UIControlStateNormal];
... ... @@ -120,21 +125,48 @@
120 125 button.layer.borderWidth = 1;
121 126 [self.captureView addSubview:button];
122 127 return button;
  128 +
123 129 }
124   -#pragma mark - initialization
125 130  
  131 +#pragma mark - initialization
126 132 - (void)setStreamerCfg
127 133 {
128   - _kitCN.videoInitBitrate = 900;
129   - _kitCN.videoMaxBitrate = 900;
130   - _kitCN.videoMinBitrate = 300;
131   - _kitCN.maxKeyInterval = 2;
132   - _kitCN.audiokBPS = 48;
  134 + //采集配置
  135 + _kitCN.capPreset = AVCaptureSessionPreset640x480;
  136 + _kitCN.previewDimension = CGSizeMake(360, 640);
  137 + _kitCN.streamDimension = CGSizeMake(360, 640);
133 138 _kitCN.videoFPS = 15;
134   - _kitCN.enAutoApplyEstimateBW = YES;
135   - _kitCN.isOpenImageFilter = YES;
136   - [_kitCN setVideoOrientationBy:UIInterfaceOrientationPortrait];
  139 + _kitCN.cameraPosition = AVCaptureDevicePositionFront;
  140 +
  141 + //推流配置
  142 + _kitCN.streamerBase.videoCodec = CNLiveVideoCodec_AUTO;
  143 + _kitCN.streamerBase.videoInitBitrate = 900;
  144 + _kitCN.streamerBase.videoMaxBitrate = 900;
  145 + _kitCN.streamerBase.videoMinBitrate = 300;
  146 + _kitCN.streamerBase.maxKeyInterval = 2;
  147 + _kitCN.streamerBase.audiokBPS = 48;
  148 +
  149 + //耳返
  150 + if ([CNLiveAudioCapture isHeadsetPluggedIn]) {
  151 + [_kitCN.audioCapture setBPlayCapturedAudio:YES];
  152 + }
  153 +
  154 + //设置画面朝向
  155 + [_kitCN setVideoOrientationBy:[[UIApplication sharedApplication] statusBarOrientation]];
137 156 [_kitCN startPreview:self.captureView];
  157 +
  158 + //水印图片
  159 + _kitCN.watermark.logoPic = [UIImage imageNamed:@"互动电视180x180"];
  160 + _kitCN.watermark.logoRect = CGRectMake(0.8, 0.8, 50, 50);
  161 + _kitCN.watermark.logoAlpha = 0.6;
  162 +
  163 + //水印文字
  164 + _kitCN.watermark.textLabel = [[UILabel alloc] init];
  165 + _kitCN.watermark.textLabel.text = [NSString stringWithFormat:@"cnlive"];
  166 + _kitCN.watermark.textLabel.font = [UIFont systemFontOfSize:8];
  167 + _kitCN.watermark.textRect = CGRectMake(0.78, 0.88, 0.2, 0.04);
  168 + [_kitCN.watermark updateTextLabel];
  169 +
138 170 }
139 171  
140 172 #pragma mark - Action
... ... @@ -182,8 +214,34 @@
182 214  
183 215 - (void)openFilter:(UIButton *)button
184 216 {
185   - _kitCN.isOpenImageFilter = button.selected;
186 217 button.selected = !button.selected;
  218 +
  219 + if (button.selected) {
  220 +
  221 + _filterView.hidden = NO;
  222 +
  223 + __weak StreamerDetailViewController *weakself = self;
  224 +
  225 + _filterView.filterViewBlock = ^(float grindRatio , float whitenRatio, float intensity){
  226 +
  227 + [weakself.kitCN.beautifyFaceFilter filterAdjustingParameterWithGrindRatio:grindRatio
  228 + whitenRatio:whitenRatio
  229 + intensity:intensity];
  230 + };
  231 +
  232 + _filterView.currentTypeBlock = ^(NSInteger currentType){
  233 + [weakself.kitCN.beautifyFaceFilter setBeautyType:currentType];
  234 + };
  235 +
  236 + _filterView.currentIdxBlock = ^(NSInteger currentIdx){
  237 + weakself.kitCN.beautifyFaceFilter.curEffectIdx = currentIdx;
  238 + };
  239 +
  240 + } else {
  241 +
  242 + _filterView.hidden = YES;
  243 +
  244 + }
187 245 }
188 246  
189 247 - (void)changeCamera:(UIButton *)button
... ... @@ -195,6 +253,7 @@
195 253 // _kitCN.cameraPosition = AVCaptureDevicePositionFront;
196 254 // }
197 255 [_kitCN switchCamera];
  256 +
198 257 }
199 258  
200 259 - (void)openFlash
... ... @@ -215,8 +274,38 @@
215 274 [self dismissViewControllerAnimated:YES completion:NULL];
216 275 }
217 276  
  277 +- (void)addObservers
  278 +{
  279 + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(captureStateChange) name:CNLiveCaptureStateDidChangeNotification object:nil];
  280 +
  281 + [[NSNotificationCenter defaultCenter] addObserver:self
  282 + selector:@selector(streamStateChange)
  283 + name:CNLiveStreamStateDidChangeNotification
  284 + object:nil];
  285 +
  286 + [[NSNotificationCenter defaultCenter] addObserver:self
  287 + selector:@selector(enterBg)
  288 + name:UIApplicationDidEnterBackgroundNotification
  289 + object:nil];
  290 +
  291 + [[NSNotificationCenter defaultCenter] addObserver:self
  292 + selector:@selector(becameActive)
  293 + name:UIApplicationDidBecomeActiveNotification
  294 + object:nil];
  295 +}
  296 +
218 297 #pragma mark - notification
219 298  
  299 +- (void)enterBg
  300 +{
  301 + [_kitCN appEnterBackground];
  302 +}
  303 +
  304 +- (void)becameActive
  305 +{
  306 + [_kitCN appBecomeActive];
  307 +}
  308 +
220 309 - (void)captureStateChange
221 310 {
222 311  
... ... @@ -297,19 +386,14 @@
297 386 _stateLab.text = @"CNLiveStopStreamSuccess";
298 387  
299 388 }
300   -
301   - //结束推流成功
302   - if ( _kitCN.streamState == CNLiveStopStreamFailure) {
303   - NSLog(@"---------CNLiveStopStreamSuccess");
304   - _stateLab.text = @"CNLiveStopStreamFailure";
305   -
306   - }
307 389 }
308 390  
309 391 - (void)onStreamError {
310 392  
311 393 CNLiveStreamErrorCode err = _kitCN.streamErrorCode;
312 394  
  395 + NSLog(@"onErr: %lu [%@]", (unsigned long) err, _stateLab.text);
  396 +
313 397 if ( CNLiveStreamErrorCode_CNLiveAUTHFAILED == err ) {
314 398 _stateLab.text = @"SDK auth failed, \npls check ak/sk";
315 399 }
... ... @@ -326,61 +410,110 @@
326 410 _stateLab.text = @"CNLiveStreamErrorCode_ABNORMAL";
327 411 [self toast:@"推流异常中断~~"];
328 412 _startLiveBtn.selected = NO;
  413 +
  414 + } else if (err == CNLiveStreamErrorCode_CODEC_OPEN_FAILED) {
  415 + NSLog(@"video codec open failed, try software codec");
  416 + _kitCN.streamerBase.videoCodec = CNLiveVideoCodec_VT264;
  417 + [self tryReconnect];
329 418 }
330 419 else {
331 420  
332 421 }
333   - NSLog(@"onErr: %lu [%@]", (unsigned long) err, _stateLab.text);
  422 +
334 423 // 断网重连
335   - if ( CNLiveStreamErrorCode_CONNECT_BREAK == err) {
336   - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
337   -
338   - [_kitCN stopStream];
  424 + if (err == CNLiveStreamErrorCode_CONNECT_BREAK || err == CNLiveStreamErrorCode_AV_SYNC_ERROR) {
  425 + [self tryReconnect];
  426 + }
  427 +
  428 +}
  429 +
  430 +- (void) tryReconnect
  431 +{
  432 + dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC));
  433 + dispatch_after(delay, dispatch_get_main_queue(), ^{
  434 +
  435 + NSLog(@"try again");
  436 +
  437 + [_kitCN stopStream];
  438 +
  439 + if (_isAuthLive) {
339 440  
340   - if (_isAuthLive) {
341   -
342   - [_kitCN startStream:^{
343   - NSLog(@"开启推流成功 ------- success");
344   - } failure:^(NSDictionary *errorDic) {
345   - [self toast:errorDic[@"errorMessage"]];
346   - _startLiveBtn.selected = NO;
347   - }];
  441 + [_kitCN startStream:^{
  442 + NSLog(@"开启推流成功 ------- success");
  443 + _startLiveBtn.selected = YES;
348 444  
349   - }else{
350   - [_kitCN startStream:_hostURL];
351   - }
352   - });
353   - }
  445 + } failure:^(NSDictionary *errorDic) {
  446 + [self toast:errorDic[@"errorMessage"]];
  447 + _startLiveBtn.selected = NO;
  448 + }];
  449 +
  450 + }else{
  451 + [_kitCN startStream:_hostURL];
  452 + }
  453 +
  454 +
  455 + });
354 456 }
355 457  
356   -//对焦
  458 +//对焦与曝光
357 459 - (void)onTap:(UIGestureRecognizer *)sender
358 460 {
359   - CGPoint point = [sender locationInView:self.view];
360   - CGPoint tap;
361   - tap.x = (point.x/Width);
362   - tap.y = (point.y/Height);
363   -
364   - NSError __autoreleasing *error;
365   - [self focusAtPoint:tap error:&error];
  461 + CGPoint current = [sender locationInView:self.view];
  462 + CGPoint point = [self convertToPointOfInterestFromViewCoordinates:current];
  463 + [_kitCN exposureAtPoint:point];
  464 + [_kitCN focusAtPoint:point];
366 465 }
367 466  
368   -- (BOOL)focusAtPoint:(CGPoint )point error:(NSError *__autoreleasing* )error
  467 +//缩放
  468 +- (void)pinchDetected:(UIPinchGestureRecognizer *)recognizer{
  469 + if (recognizer.state == UIGestureRecognizerStateBegan) {
  470 + _currentPinchZoomFactor = _kitCN.pinchZoomFactor;
  471 + }
  472 + CGFloat zoomFactor = _currentPinchZoomFactor * recognizer.scale;//当前触摸缩放因子*坐标比例
  473 + [_kitCN setPinchZoomFactor:zoomFactor];
  474 +}
  475 +
  476 +/**
  477 + @abstract 将UI的坐标转换成相机坐标
  478 + */
  479 +- (CGPoint)convertToPointOfInterestFromViewCoordinates:(CGPoint)viewCoordinates
369 480 {
370   - AVCaptureDevice *dev = [_kitCN getCurrentCameraDevices];
371   - if ([dev isFocusPointOfInterestSupported] && [dev isFocusModeSupported:AVCaptureFocusModeAutoFocus]) {
372   - if ([dev lockForConfiguration:error]) {
373   - [dev setFocusPointOfInterest:point];
374   - [dev setFocusMode:AVCaptureFocusModeAutoFocus];
375   - [dev unlockForConfiguration];
376   - return YES;
  481 + CGPoint pointOfInterest = CGPointMake(.5f, .5f);
  482 + CGSize frameSize = self.view.frame.size;
  483 + CGSize apertureSize = [_kitCN captureDimension];
  484 + CGPoint point = viewCoordinates;
  485 + CGFloat apertureRatio = apertureSize.height / apertureSize.width;
  486 + CGFloat viewRatio = frameSize.width / frameSize.height;
  487 + CGFloat xc = .5f;
  488 + CGFloat yc = .5f;
  489 +
  490 + if (viewRatio > apertureRatio) {
  491 + CGFloat y2 = frameSize.height;
  492 + CGFloat x2 = frameSize.height * apertureRatio;
  493 + CGFloat x1 = frameSize.width;
  494 + CGFloat blackBar = (x1 - x2) / 2;
  495 + if (point.x >= blackBar && point.x <= blackBar + x2) {
  496 + xc = point.y / y2;
  497 + yc = 1.f - ((point.x - blackBar) / x2);
  498 + }
  499 + }else {
  500 + CGFloat y2 = frameSize.width / apertureRatio;
  501 + CGFloat y1 = frameSize.height;
  502 + CGFloat x2 = frameSize.width;
  503 + CGFloat blackBar = (y1 - y2) / 2;
  504 + if (point.y >= blackBar && point.y <= blackBar + y2) {
  505 + xc = ((point.y - blackBar) / y2);
  506 + yc = 1.f - (point.x / x2);
377 507 }
378 508 }
379   - return NO;
  509 + pointOfInterest = CGPointMake(xc, yc);
  510 + return pointOfInterest;
380 511 }
381 512  
  513 +
382 514 - (void)toast:(NSString*)message
383 515 {
  516 +
384 517 UIAlertView *toast = [[UIAlertView alloc] initWithTitle:nil
385 518 message:message
386 519 delegate:nil
... ... @@ -398,15 +531,37 @@
398 531 - (UIView *)captureView
399 532 {
400 533 if (!_captureView) {
401   - _captureView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, Width, Height)];
  534 + _captureView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];
402 535 _captureView.backgroundColor = [UIColor blackColor];
403 536 }
404 537 return _captureView;
405 538 }
406 539  
  540 +- (UILabel *)stateLab
  541 +{
  542 + if (!_stateLab) {
  543 + _stateLab = [[UILabel alloc] initWithFrame:CGRectMake(0, Height-100, Width, 100)];
  544 + _stateLab.backgroundColor = [UIColor clearColor];
  545 + _stateLab.numberOfLines = 0;
  546 + _stateLab.textColor = [UIColor redColor];
  547 + }
  548 + return _stateLab;
  549 +}
  550 +
  551 +- (FilterFunctionView *)filterView
  552 +{
  553 + if (!_filterView) {
  554 + _filterView = [[FilterFunctionView alloc] initWithFrame:CGRectMake(0, 170, Width, 200)];
  555 + _filterView.hidden = YES;
  556 + }
  557 + return _filterView;
  558 +}
407 559 - (void)dealloc
408 560 {
409 561 [[NSNotificationCenter defaultCenter] removeObserver:self];
  562 +
  563 + [[NSNotificationCenter defaultCenter] removeObserver:self name:CNLiveCaptureStateDidChangeNotification object:nil];
  564 +
410 565 self.kitCN = nil;
411 566 }
412 567  
... ...
CNLivePlayerSDKTest/CNLivePlayerSDKTest/Streamer/StreamerViewController.m
... ... @@ -217,13 +217,13 @@
217 217 }
218 218  
219 219 /*
220   -#pragma mark - Navigation
221   -
222   -// In a storyboard-based application, you will often want to do a little preparation before navigation
223   -- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
224   - // Get the new view controller using [segue destinationViewController].
225   - // Pass the selected object to the new view controller.
226   -}
227   -*/
  220 + #pragma mark - Navigation
  221 +
  222 + // In a storyboard-based application, you will often want to do a little preparation before navigation
  223 + - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
  224 + // Get the new view controller using [segue destinationViewController].
  225 + // Pass the selected object to the new view controller.
  226 + }
  227 + */
228 228  
229 229 @end
... ...
CNLivePlayerSDKTest/KSYGPUResource.bundle/1_xiaoqingxin.png 0 → 100755

571 KB

CNLivePlayerSDKTest/KSYGPUResource.bundle/2_liangli.png 0 → 100755

677 KB

CNLivePlayerSDKTest/KSYGPUResource.bundle/3_tianmeikeren.png 0 → 100755

488 KB

CNLivePlayerSDKTest/KSYGPUResource.bundle/4_huaijiu.png 0 → 100755

598 KB

CNLivePlayerSDKTest/KSYGPUResource.bundle/5_landiao.png 0 → 100755

726 KB

CNLivePlayerSDKTest/KSYGPUResource.bundle/6_laozhaop.png 0 → 100755

303 KB

CNLivePlayerSDKTest/KSYGPUResource.bundle/Info.plist 0 → 100755
No preview for this file type
CNLivePlayerSDKTest/KSYGPUResource.bundle/whiten.png 0 → 100755

700 KB