Commit de05ddb643dc8ed460e4cbfdd10f4143bd5f5efc
1 parent
df821378
no message
Showing
82 changed files
with
4265 additions
and
304 deletions
CNLivePlayer/Classes/Header/CNLivePlayerDefines.h
| ... | ... | @@ -326,4 +326,13 @@ typedef NS_ENUM(NSInteger, CNLiveRecordError) { |
| 326 | 326 | }; |
| 327 | 327 | |
| 328 | 328 | |
| 329 | +/* | |
| 330 | + * 播放器类型 | |
| 331 | + */ | |
| 332 | +typedef NS_ENUM(NSUInteger, CNLiveStreamerType) { | |
| 333 | + CNLiveStreamerVod, //视频 | |
| 334 | + CNLiveStreamerAudio //音频 | |
| 335 | + | |
| 336 | +}; | |
| 337 | + | |
| 329 | 338 | #endif /* CNLivePlayerDefines_h */ | ... | ... |
CNLivePlayer/Classes/Player/CNLivePlayerUrl.h
| ... | ... | @@ -8,9 +8,10 @@ |
| 8 | 8 | |
| 9 | 9 | #ifndef CNLivePlayerUrl_h |
| 10 | 10 | #define CNLivePlayerUrl_h |
| 11 | +#import "CNLivePlayerManager.h" | |
| 11 | 12 | |
| 12 | -#pragma mark - 版本号 | |
| 13 | -#define PlayerSDKVersion @"0.0.1" //播放器SDK版本 | |
| 13 | +#pragma mark - 播放器版本号 | |
| 14 | +#define PlayerSDKVersion @"0.0.1" | |
| 14 | 15 | |
| 15 | 16 | #pragma mark - 探针 |
| 16 | 17 | #define StatUrl [CNLivePlayerManager manager].isTestEnvironment?@"http://app.sta.cnlive.com/app.jpg": @"http://app.sta.cnlive.com/app.jpg" | ... | ... |
CNLivePlayer/Classes/Streamer/CNLiveStreamerKit.h
| ... | ... | @@ -20,21 +20,48 @@ NS_ASSUME_NONNULL_BEGIN |
| 20 | 20 | |
| 21 | 21 | |
| 22 | 22 | @interface CNLiveStreamerKit : NSObject |
| 23 | +#pragma mark - 初始化方法 | |
| 23 | 24 | /** |
| 24 | 25 | @abstract 初始化(不会打断其他后台的音乐播放) |
| 25 | 26 | @warning 实例化的对象必须赋值给一个全局变量 |
| 26 | - @param mode YES:纯音频推流 | |
| 27 | 27 | @warning 必传参数 |
| 28 | 28 | */ |
| 29 | -- (instancetype)initWithDefaultConfigWithPureAudioMode:(BOOL)mode; | |
| 29 | +- (instancetype)initPureAudioStreamerWithDefaultConfig; | |
| 30 | 30 | |
| 31 | 31 | /** |
| 32 | 32 | @abstract 初始化(会打断其他后台的音乐播放) |
| 33 | 33 | @warning 实例化的对象必须赋值给一个全局变量 |
| 34 | - @param mode YES:纯音频推流 | |
| 35 | 34 | @warning 必传参数 |
| 36 | 35 | */ |
| 37 | -- (instancetype)initWithInterruptConfigWithPureAudioMode:(BOOL)mode; | |
| 36 | +- (instancetype)initPureAudioStreamerWithInterruptConfig; | |
| 37 | + | |
| 38 | +/** | |
| 39 | + @abstract 初始化(不会打断其他后台的音乐播放) | |
| 40 | + @warning 实例化的对象必须赋值给一个全局变量 | |
| 41 | + @warning 必传参数 | |
| 42 | + */ | |
| 43 | +- (instancetype)initVodStreamerWithDefaultConfig; | |
| 44 | + | |
| 45 | +/** | |
| 46 | + @abstract 初始化(会打断其他后台的音乐播放) | |
| 47 | + @warning 实例化的对象必须赋值给一个全局变量 | |
| 48 | + @warning 必传参数 | |
| 49 | + */ | |
| 50 | +- (instancetype)initVodStreamerWithInterruptConfig; | |
| 51 | + | |
| 52 | +/** | |
| 53 | + @abstract 普通推流初始化(不会打断其他后台的音乐播放) | |
| 54 | + @warning 实例化的对象必须赋值给一个全局变量 | |
| 55 | + @warning 必传参数 | |
| 56 | + */ | |
| 57 | +- (instancetype)initWithDefaultConfig:(BOOL)pureAudioMode; | |
| 58 | + | |
| 59 | +/** | |
| 60 | + @abstract 普通推流初始化(会打断其他后台的音乐播放) | |
| 61 | + @warning 实例化的对象必须赋值给一个全局变量 | |
| 62 | + @warning 必传参数 | |
| 63 | + */ | |
| 64 | +- (instancetype)initWithInterruptConfig:(BOOL)pureAudioMode; | |
| 38 | 65 | |
| 39 | 66 | /** |
| 40 | 67 | @abstract 活动ID,确保SP下的唯一性 |
| ... | ... | @@ -55,7 +82,7 @@ NS_ASSUME_NONNULL_BEGIN |
| 55 | 82 | @property (nonatomic, assign) BOOL logPrintEnable; |
| 56 | 83 | |
| 57 | 84 | /** |
| 58 | - @abstract 屏幕方向,0:垂直即竖屏 /1:水平即横屏 ,默认为0 | |
| 85 | + @abstract 屏幕方向,0:垂直即竖屏 1:水平即横屏 ,默认为0 | |
| 59 | 86 | */ |
| 60 | 87 | @property (nonatomic, assign) BOOL isHorizontalScreen; |
| 61 | 88 | |
| ... | ... | @@ -65,7 +92,7 @@ NS_ASSUME_NONNULL_BEGIN |
| 65 | 92 | @property (nonatomic, strong) NSString *activityName; |
| 66 | 93 | |
| 67 | 94 | /** |
| 68 | - @abstract 活动状态,0:未开始 /1:已开始 /3:已结束 /4 已下线,默认为0(非必传) | |
| 95 | + @abstract 活动状态,0:未开始 1:已开始 3:已结束 4:已下线,默认为0(非必传) | |
| 69 | 96 | */ |
| 70 | 97 | @property (nonatomic, strong) NSString *activityStatus; |
| 71 | 98 | |
| ... | ... | @@ -124,22 +151,6 @@ NS_ASSUME_NONNULL_BEGIN |
| 124 | 151 | */ |
| 125 | 152 | FOUNDATION_EXPORT NSString *const CNLiveServiceConnectBreakNotification NS_AVAILABLE_IOS(7_0); |
| 126 | 153 | |
| 127 | -#pragma mark - 普通推流 | |
| 128 | - | |
| 129 | -/** | |
| 130 | - @abstract 初始化(不会打断其他后台的音乐播放) | |
| 131 | - @param mode YES:纯音频推流 | |
| 132 | - @warning 实例化的对象必须赋值给一个全局变量 | |
| 133 | - */ | |
| 134 | -- (instancetype)initWithDefaultConfigWithPureAudioMode:(BOOL)mode; | |
| 135 | - | |
| 136 | -/** | |
| 137 | - @abstract 初始化(会打断其他后台的音乐播放) | |
| 138 | - @param mode YES:纯音频推流 | |
| 139 | - @warning 实例化的对象必须赋值给一个全局变量 | |
| 140 | - */ | |
| 141 | -- (instancetype)initWithInterruptConfigWithPureAudioMode:(BOOL)mode; | |
| 142 | - | |
| 143 | 154 | /** |
| 144 | 155 | * 预览视图 |
| 145 | 156 | */ |
| ... | ... | @@ -213,7 +224,7 @@ FOUNDATION_EXPORT NSString *const CNLiveServiceConnectBreakNotification NS_AVAIL |
| 213 | 224 | @abstract 采集及编码视频帧率 (开始采集前设置有效) |
| 214 | 225 | @discussion video frame per seconds 有效范围[1~30], 超出范围会取边界有效值 |
| 215 | 226 | @discussion 默认值为15 */ |
| 216 | -@property (nonatomic, assign) int videoFPS; | |
| 227 | +@property (nonatomic, assign) int videoFPS; | |
| 217 | 228 | |
| 218 | 229 | /** |
| 219 | 230 | @abstract 摄像头位置 |
| ... | ... | @@ -227,7 +238,7 @@ FOUNDATION_EXPORT NSString *const CNLiveServiceConnectBreakNotification NS_AVAIL |
| 227 | 238 | @return AVCaptureDevice* 预览开始前调用返回为nil,开始预览后,返回当前正在使用的摄像头 |
| 228 | 239 | @warning 请勿修改摄像头的像素格式,帧率,分辨率等参数,修改后会导致推流工作异常或崩溃 |
| 229 | 240 | */ |
| 230 | -- (AVCaptureDevice *) getCurrentCameraDevices; | |
| 241 | +- (AVCaptureDevice *)getCurrentCameraDevices; | |
| 231 | 242 | |
| 232 | 243 | /** |
| 233 | 244 | @abstract 采集设备状态 |
| ... | ... | @@ -243,7 +254,7 @@ FOUNDATION_EXPORT NSString *const CNLiveCaptureStateDidChangeNotification NS_AVA |
| 243 | 254 | */ |
| 244 | 255 | @property (nonatomic, readonly) CNLiveStreamState streamState; |
| 245 | 256 | |
| 246 | -FOUNDATION_EXPORT NSString *const CNLiveStreamStateDidChangeNotification NS_AVAILABLE_IOS(7_0); | |
| 257 | +FOUNDATION_EXPORT NSString *const CNLiveStreamerStateDidChangeNotification NS_AVAILABLE_IOS(7_0); | |
| 247 | 258 | |
| 248 | 259 | /** |
| 249 | 260 | * @abstract 推流错误码,用于指示推流失败的原因 |
| ... | ... | @@ -257,7 +268,7 @@ FOUNDATION_EXPORT NSString *const CNLiveStreamStateDidChangeNotification NS_AVAI |
| 257 | 268 | @discussion 若filter 为GPUImageFilter的实例,则使用该滤镜做处理 |
| 258 | 269 | @discussion filter 也可以是GPUImageFilterGroup的实例,可以将多个滤镜组合 |
| 259 | 270 | */ |
| 260 | -- (void)setupFilter:(GPUImageOutput<GPUImageInput>*) filter; | |
| 271 | +- (void)setupFilter:(GPUImageOutput<GPUImageInput>*)filter; | |
| 261 | 272 | |
| 262 | 273 | #pragma mark - reconnect |
| 263 | 274 | /** |
| ... | ... | @@ -288,7 +299,7 @@ FOUNDATION_EXPORT NSString *const CNLiveStreamStateDidChangeNotification NS_AVAI |
| 288 | 299 | CNLiveStreamErrorCode_CODEC_OPEN_FAILED、 |
| 289 | 300 | CNLiveStreamErrorCode_ABNORMAL 时为可重连状态; |
| 290 | 301 | */ |
| 291 | -FOUNDATION_EXPORT NSString *const CNLiveStreamReconnectStatusChangedNotification NS_AVAILABLE_IOS(7_0); | |
| 302 | +FOUNDATION_EXPORT NSString *const CNLiveStreamerReconnectStatusChangedNotification NS_AVAILABLE_IOS(7_0); | |
| 292 | 303 | |
| 293 | 304 | /** |
| 294 | 305 | @abstract 切换摄像头 |
| ... | ... | @@ -327,7 +338,7 @@ FOUNDATION_EXPORT NSString *const CNLiveStreamReconnectStatusChangedNotification |
| 327 | 338 | @discussion 需要访问摄像头和麦克风的权限,若授权失败,其他API都会拒绝服务 |
| 328 | 339 | @warning: 开始推流前必须先启动预览 |
| 329 | 340 | */ |
| 330 | -- (void)startPreview:(UIView*) view; | |
| 341 | +- (void)startPreview:(UIView *)view; | |
| 331 | 342 | |
| 332 | 343 | /** |
| 333 | 344 | @abstract 停止预览,停止采集设备,并清理会话 |
| ... | ... | @@ -392,25 +403,25 @@ FOUNDATION_EXPORT NSString *const CNLiveStreamReconnectStatusChangedNotification |
| 392 | 403 | @param orie 旋转到目标朝向, 需要从demo中获取UI的朝向传入 |
| 393 | 404 | @discussion 采集到的图像的朝向还是和启动时的朝向一致 |
| 394 | 405 | */ |
| 395 | -- (void) rotatePreviewTo: (UIInterfaceOrientation) orie; | |
| 406 | +- (void)rotatePreviewTo:(UIInterfaceOrientation) orie; | |
| 396 | 407 | |
| 397 | 408 | /** |
| 398 | 409 | @abstract 根据UI的朝向旋转推流画面 |
| 399 | 410 | @param orie 旋转到目标朝向, 需要从demo中获取UI的朝向传入 |
| 400 | 411 | */ |
| 401 | -- (void) rotateStreamTo: (UIInterfaceOrientation) orie; | |
| 412 | +- (void)rotateStreamTo:(UIInterfaceOrientation) orie; | |
| 402 | 413 | |
| 403 | 414 | /** |
| 404 | 415 | @abstract 当前采集设备是否支持自动变焦 |
| 405 | 416 | @param point 相机对焦的位置 |
| 406 | 417 | */ |
| 407 | -- (void)focusAtPoint:(CGPoint )point; | |
| 418 | +- (void)focusAtPoint:(CGPoint)point; | |
| 408 | 419 | |
| 409 | 420 | /** |
| 410 | 421 | @abstract 当前采集设备是否支持自动曝光 |
| 411 | 422 | @param point 相机曝光的位置 |
| 412 | 423 | */ |
| 413 | -- (void)exposureAtPoint:(CGPoint )point; | |
| 424 | +- (void)exposureAtPoint:(CGPoint)point; | |
| 414 | 425 | |
| 415 | 426 | /** |
| 416 | 427 | @abstract 触摸缩放因子 | ... | ... |
CNLivePlayer/Classes/Streamer/CNLiveStreamerKit.m
| ... | ... | @@ -18,21 +18,27 @@ |
| 18 | 18 | #import "CNLiveBgmPlayer.h" |
| 19 | 19 | #import "CNLivePlayerManager.h" |
| 20 | 20 | #import "CNLiveStreamerTools.h" |
| 21 | +#import "CNLivePlayerNetworkManager.h" | |
| 22 | + | |
| 23 | +#import "CNLiveStreamerUrl.h" | |
| 24 | + | |
| 25 | +#define Host @"bc.cnlive.com" | |
| 26 | +#define Port 65432 | |
| 21 | 27 | |
| 22 | 28 | //采集状态通知 |
| 23 | 29 | NSString * const CNLiveCaptureStateDidChangeNotification = @"CNLiveCaptureStateDidChangeNotification"; |
| 24 | 30 | |
| 25 | 31 | //推流状态通知 |
| 26 | -NSString * const CNLiveStreamStateDidChangeNotification = @"CNLiveStreamStateDidChangeNotification"; | |
| 32 | +NSString * const CNLiveStreamerStateDidChangeNotification = @"CNLiveStreamerStateDidChangeNotification"; | |
| 27 | 33 | |
| 28 | 34 | //自动重连失败通知 |
| 29 | -NSString * const CNLiveStreamReconnectStatusChangedNotification = @"CNLiveStreamReconnectStatusChangedNotification"; | |
| 35 | +NSString * const CNLiveStreamerReconnectStatusChangedNotification = @"CNLiveStreamerReconnectStatusChangedNotification"; | |
| 30 | 36 | |
| 31 | 37 | //获取直播时长通知 |
| 32 | -NSString * const CNLiveStreamGetDurationNotification = @"CNLiveStreamGetDurationNotification"; | |
| 38 | +NSString * const CNLiveStreamerGetDurationNotification = @"CNLiveStreamerGetDurationNotification"; | |
| 33 | 39 | |
| 34 | 40 | //收到消息通知 |
| 35 | -NSString * const MsgToolsStreamReceiveNotification = @"CNLiveMsgToolsPlayerReceiveNotification"; | |
| 41 | +NSString * const CNLiveStreamerMsgReceiveNotification = @"CNLiveMsgToolsPlayerReceiveNotification"; | |
| 36 | 42 | |
| 37 | 43 | //由服务端断开 |
| 38 | 44 | NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectBreakNotification"; |
| ... | ... | @@ -42,7 +48,6 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 42 | 48 | BOOL _activitySuccess; //活动是否创建成功 |
| 43 | 49 | BOOL _isCNLiveStreaming; //是否为视讯云平台推流 |
| 44 | 50 | |
| 45 | - BOOL _noti; | |
| 46 | 51 | BOOL _pureAudioMode; //是否为纯音频推流 |
| 47 | 52 | |
| 48 | 53 | int _autoRetryCnt; //记录重试次数 |
| ... | ... | @@ -54,6 +59,7 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 54 | 59 | NSString *_contentId; |
| 55 | 60 | NSString *_roomId; |
| 56 | 61 | int _originalStatus; //原始状态 |
| 62 | + | |
| 57 | 63 | CNLiveStreamerManager *_manager; |
| 58 | 64 | |
| 59 | 65 | BOOL _enterBackground; |
| ... | ... | @@ -74,66 +80,132 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 74 | 80 | @end |
| 75 | 81 | |
| 76 | 82 | @implementation CNLiveStreamerKit |
| 83 | +#pragma mark - 初始化方法 | |
| 77 | 84 | /** |
| 78 | - @abstract 初始化(不会打断其他后台的音乐播放) | |
| 85 | + @abstract 纯音频推流初始化(不会打断其他后台的音乐播放) | |
| 79 | 86 | @warning 实例化的对象必须赋值给一个全局变量 |
| 80 | - @param mode YES:纯音频推流 | |
| 81 | 87 | @warning 必传参数 |
| 82 | 88 | */ |
| 83 | -- (instancetype)initWithDefaultConfigWithPureAudioMode:(BOOL)mode{ | |
| 89 | +- (instancetype)initPureAudioStreamerWithDefaultConfig{ | |
| 84 | 90 | if (self = [super init]) { |
| 85 | 91 | _logPrintEnable = YES; |
| 86 | - _pureAudioMode = mode; | |
| 92 | + _pureAudioMode = YES; | |
| 87 | 93 | _autoRetryCnt = 0; |
| 88 | 94 | _autoRetryDelay = 2.0; |
| 89 | 95 | |
| 90 | -// _parameter = [[NSMutableDictionary alloc] init]; | |
| 91 | - [self setStreamerCfgWithInterrupt:NO]; | |
| 92 | -// | |
| 93 | -// //视讯云直播,注册前后台切换通知 | |
| 94 | -// [self addStatusChangedObservers]; | |
| 96 | + _parameter = [[NSMutableDictionary alloc] init]; | |
| 97 | + [self setStreamerWithConfig:NO]; | |
| 98 | + | |
| 99 | + //视讯云直播,注册前后台切换通知 | |
| 100 | + [self addStatusChangedObservers]; | |
| 95 | 101 | |
| 96 | 102 | } |
| 97 | 103 | return self; |
| 98 | 104 | } |
| 99 | 105 | |
| 100 | 106 | /** |
| 101 | - @abstract 初始化(会打断其他后台的音乐播放) | |
| 107 | + @abstract 纯音频推流初始化(会打断其他后台的音乐播放) | |
| 102 | 108 | @warning 实例化的对象必须赋值给一个全局变量 |
| 103 | - @param mode YES:纯音频推流 | |
| 104 | 109 | @warning 必传参数 |
| 105 | 110 | */ |
| 106 | -- (instancetype)initWithInterruptConfigWithPureAudioMode:(BOOL)mode{ | |
| 111 | +- (instancetype)initPureAudioStreamerWithInterruptConfig{ | |
| 107 | 112 | if (self = [super init]) { |
| 108 | 113 | _logPrintEnable = YES; |
| 109 | - _pureAudioMode = mode; | |
| 114 | + _pureAudioMode = YES; | |
| 110 | 115 | _autoRetryCnt = 0; |
| 111 | 116 | _autoRetryDelay = 2.0; |
| 112 | 117 | |
| 113 | -// _parameter = [[NSMutableDictionary alloc] init]; | |
| 114 | - [self setStreamerCfgWithInterrupt:YES]; | |
| 115 | -// | |
| 116 | -// //视讯云直播,注册前后台切换通知 | |
| 117 | -// [self addStatusChangedObservers]; | |
| 118 | + _parameter = [[NSMutableDictionary alloc] init]; | |
| 119 | + [self setStreamerWithConfig:NO]; | |
| 120 | + | |
| 121 | + //视讯云直播,注册前后台切换通知 | |
| 122 | + [self addStatusChangedObservers]; | |
| 123 | + | |
| 124 | + } | |
| 125 | + return self; | |
| 126 | +} | |
| 127 | + | |
| 128 | +/** | |
| 129 | + @abstract 音视频推流初始化(不会打断其他后台的音乐播放) | |
| 130 | + @warning 实例化的对象必须赋值给一个全局变量 | |
| 131 | + @warning 必传参数 | |
| 132 | + */ | |
| 133 | +- (instancetype)initVodStreamerWithDefaultConfig{ | |
| 134 | + if (self = [super init]) { | |
| 135 | + _logPrintEnable = YES; | |
| 136 | + _pureAudioMode = NO; | |
| 137 | + _autoRetryCnt = 0; | |
| 138 | + _autoRetryDelay = 2.0; | |
| 139 | + | |
| 140 | + _parameter = [[NSMutableDictionary alloc] init]; | |
| 141 | + [self setStreamerWithConfig:NO]; | |
| 142 | + | |
| 143 | + //视讯云直播,注册前后台切换通知 | |
| 144 | + [self addStatusChangedObservers]; | |
| 118 | 145 | |
| 119 | 146 | } |
| 120 | 147 | return self; |
| 121 | 148 | } |
| 122 | 149 | |
| 123 | -#pragma mark - 初始化KSY | |
| 124 | -- (void)setStreamerCfgWithInterrupt:(BOOL)interrupt { | |
| 150 | +/** | |
| 151 | + @abstract 音视频推流初始化(会打断其他后台的音乐播放) | |
| 152 | + @warning 实例化的对象必须赋值给一个全局变量 | |
| 153 | + @warning 必传参数 | |
| 154 | + */ | |
| 155 | +- (instancetype)initVodStreamerWithInterruptConfig{ | |
| 156 | + if (self = [super init]) { | |
| 157 | + _logPrintEnable = YES; | |
| 158 | + _pureAudioMode = NO; | |
| 159 | + _autoRetryCnt = 0; | |
| 160 | + _autoRetryDelay = 2.0; | |
| 161 | + | |
| 162 | + _parameter = [[NSMutableDictionary alloc] init]; | |
| 163 | + [self setStreamerWithConfig:NO]; | |
| 164 | + | |
| 165 | + //视讯云直播,注册前后台切换通知 | |
| 166 | + [self addStatusChangedObservers]; | |
| 167 | + | |
| 168 | + } | |
| 169 | + return self; | |
| 170 | +} | |
| 171 | + | |
| 172 | +//普通推流 | |
| 173 | +//不会打断其他后台音乐 | |
| 174 | +- (instancetype)initWithDefaultConfig:(BOOL)pureAudioMode { | |
| 175 | + if (self = [super init]) { | |
| 176 | + _logPrintEnable = YES; | |
| 177 | + _pureAudioMode = pureAudioMode; | |
| 178 | + [self setStreamerWithConfig:NO]; | |
| 179 | + } | |
| 180 | + return self; | |
| 181 | +} | |
| 182 | + | |
| 183 | +//会打断其他后台音乐 | |
| 184 | +- (instancetype)initWithInterruptConfig:(BOOL)pureAudioMode { | |
| 185 | + if (self = [super init]) { | |
| 186 | + _logPrintEnable = YES; | |
| 187 | + _pureAudioMode = pureAudioMode; | |
| 188 | + [self setStreamerWithConfig:YES]; | |
| 189 | + } | |
| 190 | + return self; | |
| 191 | +} | |
| 192 | + | |
| 193 | +#pragma mark - 初始化推流器 | |
| 194 | +- (void)setStreamerWithConfig:(BOOL)interrupt { | |
| 125 | 195 | _manager = [CNLiveStreamerManager manager]; |
| 126 | 196 | |
| 127 | 197 | [UIApplication sharedApplication].idleTimerDisabled = YES; |
| 128 | 198 | |
| 129 | - if (interrupt) { //初始化金山kit | |
| 199 | + //初始化金山kit | |
| 200 | + if (interrupt) { | |
| 130 | 201 | _manager.kit = [[KSYGPUStreamerKit alloc] initWithInterruptCfg]; |
| 131 | 202 | } |
| 132 | 203 | else { |
| 133 | 204 | _manager.kit = [[KSYGPUStreamerKit alloc] initWithDefaultCfg]; |
| 134 | 205 | } |
| 135 | 206 | |
| 136 | - if (_pureAudioMode) { //是否为纯音频推流 | |
| 207 | + //是否为纯音频推流 | |
| 208 | + if (_pureAudioMode) { | |
| 137 | 209 | [_manager.kit.aCapDev startCapture]; |
| 138 | 210 | _manager.kit.streamerBase.bWithVideo = NO; |
| 139 | 211 | |
| ... | ... | @@ -158,21 +230,16 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 158 | 230 | }; |
| 159 | 231 | |
| 160 | 232 | //添加通知 |
| 161 | -// [self addKSYObservers]; | |
| 233 | + [self addKSYObservers]; | |
| 162 | 234 | |
| 163 | 235 | } |
| 164 | 236 | |
| 165 | 237 | #pragma mark - 通知 |
| 166 | 238 | - (void)addKSYObservers { |
| 167 | - if (_noti) return; | |
| 168 | - _noti = YES; | |
| 169 | - | |
| 170 | 239 | //采集状态通知 |
| 171 | - [[NSNotificationCenter defaultCenter] addObserver:self | |
| 172 | - selector:@selector(onCaptureStateChange) | |
| 240 | + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onCaptureStateChange) | |
| 173 | 241 | name:KSYCaptureStateDidChangeNotification |
| 174 | 242 | object:nil]; |
| 175 | - | |
| 176 | 243 | //推流状态通知 |
| 177 | 244 | [[NSNotificationCenter defaultCenter] addObserver:self |
| 178 | 245 | selector:@selector(onStreamStateChange) |
| ... | ... | @@ -219,7 +286,7 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 219 | 286 | } |
| 220 | 287 | _streamState = (CNLiveStreamState)_manager.kit.streamerBase.streamState; |
| 221 | 288 | |
| 222 | - [[NSNotificationCenter defaultCenter] postNotificationName:CNLiveStreamStateDidChangeNotification | |
| 289 | + [[NSNotificationCenter defaultCenter] postNotificationName:CNLiveStreamerStateDidChangeNotification | |
| 223 | 290 | object:nil |
| 224 | 291 | userInfo:nil]; |
| 225 | 292 | |
| ... | ... | @@ -227,7 +294,7 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 227 | 294 | |
| 228 | 295 | if (_autoRetryCnt < 3) { |
| 229 | 296 | _reconnectStatus = CNLiveReconnectStatusSuccess; |
| 230 | - [[NSNotificationCenter defaultCenter] postNotificationName:CNLiveStreamReconnectStatusChangedNotification | |
| 297 | + [[NSNotificationCenter defaultCenter] postNotificationName:CNLiveStreamerReconnectStatusChangedNotification | |
| 231 | 298 | object:nil |
| 232 | 299 | userInfo:nil]; |
| 233 | 300 | [self recoverReconnectConfig]; |
| ... | ... | @@ -240,7 +307,7 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 240 | 307 | _isRecording = NO; |
| 241 | 308 | |
| 242 | 309 | [CNLiveStreamerTools getRealTimeString:^(NSString *timeString) { |
| 243 | -// [self requestStopStreamerWithInfo:[NSString stringWithFormat:@"KSY error:%@",[_manager.kit.streamerBase getKSYStreamErrorCodeName:_manager.kit.streamerBase.streamErrorCode]] timeString:timeString]; | |
| 310 | + [self requestStopStreamerWithInfo:[NSString stringWithFormat:@"KSY error:%@",[_manager.kit.streamerBase getKSYStreamErrorCodeName:_manager.kit.streamerBase.streamErrorCode]] timeString:timeString]; | |
| 244 | 311 | }]; |
| 245 | 312 | |
| 246 | 313 | [CNLiveStreamerTools errorStat:@"推流出错" activityId:_activityId]; |
| ... | ... | @@ -249,7 +316,7 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 249 | 316 | if (_retryFailed && _isCNLiveStreaming) { |
| 250 | 317 | |
| 251 | 318 | _reconnectStatus = CNLiveReconnectStatusFailed; |
| 252 | - [[NSNotificationCenter defaultCenter] postNotificationName:CNLiveStreamReconnectStatusChangedNotification | |
| 319 | + [[NSNotificationCenter defaultCenter] postNotificationName:CNLiveStreamerReconnectStatusChangedNotification | |
| 253 | 320 | object:nil |
| 254 | 321 | userInfo:nil]; |
| 255 | 322 | [self recoverReconnectConfig]; |
| ... | ... | @@ -263,11 +330,8 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 263 | 330 | _manager.kit.streamerBase.streamErrorCode == KSYStreamErrorCode_DNS_Parse_failed || |
| 264 | 331 | _manager.kit.streamerBase.streamErrorCode == KSYStreamErrorCode_CODEC_OPEN_FAILED) { |
| 265 | 332 | |
| 266 | - // NSLog(@"ksyError---->autoRetryCnt:%d----initiativeRetry:%@----reteying:%@----retryFailed:%@", _autoRetryCnt, _initiativeRetry ? @"YES" : @"NO", _reteying?@"YES":@"NO", _retryFailed?@"YES":@"NO"); | |
| 267 | - | |
| 268 | 333 | if (_autoRetryCnt>0 && !_initiativeRetry) { |
| 269 | 334 | [self tryReconnect]; |
| 270 | - // NSLog(@"CNLiveGPUStreamerKit-->reconnect ----- 金山ERROR"); | |
| 271 | 335 | |
| 272 | 336 | } |
| 273 | 337 | } |
| ... | ... | @@ -283,12 +347,12 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 283 | 347 | if (![CNLiveStreamerTools isEmptyString:PLAYER_AppID] && _enterBackground == NO && _isRecording) { |
| 284 | 348 | _streamErrorCode = CNLiveStreamErrorCode_ABNORMAL; |
| 285 | 349 | _streamState = CNLiveStreamStateError; |
| 286 | - [[NSNotificationCenter defaultCenter] postNotificationName:CNLiveStreamStateDidChangeNotification | |
| 350 | + [[NSNotificationCenter defaultCenter] postNotificationName:CNLiveStreamerStateDidChangeNotification | |
| 287 | 351 | object:nil |
| 288 | 352 | userInfo:nil]; |
| 289 | 353 | |
| 290 | 354 | [CNLiveStreamerTools getRealTimeString:^(NSString *timeString) { |
| 291 | -// [self requestStopStreamerWithInfo:@"CNLiveStreamErrorCode_ABNORMAL_2" timeString:timeString]; | |
| 355 | + [self requestStopStreamerWithInfo:@"CNLiveStreamErrorCode_ABNORMAL_2" timeString:timeString]; | |
| 292 | 356 | }]; |
| 293 | 357 | |
| 294 | 358 | _isRecording = NO; |
| ... | ... | @@ -297,6 +361,7 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 297 | 361 | } |
| 298 | 362 | } |
| 299 | 363 | } else { |
| 364 | + | |
| 300 | 365 | } |
| 301 | 366 | |
| 302 | 367 | NSLog(@"CNLiveGPUStreamerKit-->推流工作状态发生变化CNLiveStreamState:%ld", (unsigned long)self.streamState); |
| ... | ... | @@ -304,9 +369,6 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 304 | 369 | } |
| 305 | 370 | |
| 306 | 371 | - (void)enterBackground { |
| 307 | - // [_manager.kit.aCapDev stopCapture]; | |
| 308 | - // NSLog(@"CNLiveGPUStreamerKit-->关闭音频采集状态"); | |
| 309 | - | |
| 310 | 372 | /** |
| 311 | 373 | * 视讯云平台:推流过程中退到后台或者锁屏情况下,需将活动状态改为“-2”,以便观众端收到主播离开的消息 |
| 312 | 374 | */ |
| ... | ... | @@ -320,7 +382,8 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 320 | 382 | }]; |
| 321 | 383 | |
| 322 | 384 | [CNLiveStreamerTools getRealTimeString:^(NSString *timeString) { |
| 323 | -// [self requestStopStreamerWithInfo:@"CNLiveStreamErrorCode_EnterBackground" timeString:timeString]; | |
| 385 | + [self requestStopStreamerWithInfo:@"CNLiveStreamErrorCode_EnterBackground" timeString:timeString]; | |
| 386 | + | |
| 324 | 387 | }]; |
| 325 | 388 | } |
| 326 | 389 | |
| ... | ... | @@ -336,15 +399,15 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 336 | 399 | * 视讯云平台:APP返回前台重新将活动状态改为“1”,若失败将推流状态改为error,并通知开发者 |
| 337 | 400 | */ |
| 338 | 401 | [CNLiveStreamerTools getRealTimeString:^(NSString *timeString) { |
| 339 | -// [self requestStartStreamer:NULL failure:^(NSDictionary *errorDic) { | |
| 340 | -// | |
| 341 | -// _streamErrorCode = CNLiveStreamErrorCode_ABNORMAL; | |
| 342 | -// _streamState = CNLiveStreamStateError; | |
| 343 | -// | |
| 344 | -// [[NSNotificationCenter defaultCenter] postNotificationName:CNLiveStreamStateDidChangeNotification | |
| 345 | -// object:nil | |
| 346 | -// userInfo:nil]; | |
| 347 | -// } timeString:timeString]; | |
| 402 | + [self requestStartStreamer:NULL failure:^(NSDictionary *errorDic) { | |
| 403 | + | |
| 404 | + _streamErrorCode = CNLiveStreamErrorCode_ABNORMAL; | |
| 405 | + _streamState = CNLiveStreamStateError; | |
| 406 | + | |
| 407 | + [[NSNotificationCenter defaultCenter] postNotificationName:CNLiveStreamerStateDidChangeNotification | |
| 408 | + object:nil | |
| 409 | + userInfo:nil]; | |
| 410 | + } timeString:timeString]; | |
| 348 | 411 | }]; |
| 349 | 412 | } |
| 350 | 413 | |
| ... | ... | @@ -416,9 +479,7 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 416 | 479 | _manager.kit.videoOrientation = uiOrien; |
| 417 | 480 | } |
| 418 | 481 | |
| 419 | -#pragma mark - | |
| 420 | 482 | #pragma mark - mirror & rotate |
| 421 | - | |
| 422 | 483 | //预览设置成镜像模式 |
| 423 | 484 | - (void)setPreviewMirrored:(BOOL)previewMirrored { |
| 424 | 485 | _manager.kit.previewMirrored = previewMirrored; |
| ... | ... | @@ -432,8 +493,7 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 432 | 493 | } |
| 433 | 494 | |
| 434 | 495 | //旋转预览视图 |
| 435 | -- (void)rotatePreviewTo:(UIInterfaceOrientation)orie | |
| 436 | -{ | |
| 496 | +- (void)rotatePreviewTo:(UIInterfaceOrientation)orie { | |
| 437 | 497 | [_manager.kit rotatePreviewTo:orie]; |
| 438 | 498 | } |
| 439 | 499 | |
| ... | ... | @@ -442,9 +502,7 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 442 | 502 | [_manager.kit rotateStreamTo:orie]; |
| 443 | 503 | } |
| 444 | 504 | |
| 445 | -#pragma mark - | |
| 446 | 505 | #pragma mark - camera operation |
| 447 | - | |
| 448 | 506 | - (BOOL)switchCamera { |
| 449 | 507 | return [_manager.kit switchCamera]; |
| 450 | 508 | } |
| ... | ... | @@ -467,7 +525,6 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 467 | 525 | [_manager.kit toggleTorch]; |
| 468 | 526 | } |
| 469 | 527 | |
| 470 | -#pragma mark - | |
| 471 | 528 | #pragma mark - reconnect(由于开启会暴露推流地址,暂不开放) |
| 472 | 529 | @synthesize maxAutoRetry = _maxAutoRetry; |
| 473 | 530 | - (void)setMaxAutoRetry:(int)maxAutoRetry { |
| ... | ... | @@ -491,9 +548,6 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 491 | 548 | |
| 492 | 549 | - (void)tryReconnect { |
| 493 | 550 | |
| 494 | - // NSLog(@"tryReconnect---->autoRetryCnt:%d----initiativeRetry:%@----reteying:%@----retryFailed:%@", _autoRetryCnt, _initiativeRetry ? @"YES" : @"NO", _reteying?@"YES":@"NO", _retryFailed?@"YES":@"NO"); | |
| 495 | - | |
| 496 | - | |
| 497 | 551 | if (_autoRetryCnt < 1) { |
| 498 | 552 | return; |
| 499 | 553 | } |
| ... | ... | @@ -504,12 +558,9 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 504 | 558 | |
| 505 | 559 | _reteying = YES; |
| 506 | 560 | |
| 507 | - // NSLog(@"tryReconnect---->autoRetryCnt:%d----initiativeRetry:%@----reteying:%@----retryFailed:%@", _autoRetryCnt, _initiativeRetry ? @"YES" : @"NO", _reteying?@"YES":@"NO", _retryFailed?@"YES":@"NO"); | |
| 508 | - | |
| 509 | - | |
| 510 | 561 | if (_autoRetryCnt == _maxAutoRetry) { |
| 511 | 562 | _reconnectStatus = CNLiveReconnectStatusStart; |
| 512 | - [[NSNotificationCenter defaultCenter] postNotificationName:CNLiveStreamReconnectStatusChangedNotification | |
| 563 | + [[NSNotificationCenter defaultCenter] postNotificationName:CNLiveStreamerReconnectStatusChangedNotification | |
| 513 | 564 | object:nil |
| 514 | 565 | userInfo:nil]; |
| 515 | 566 | } |
| ... | ... | @@ -519,13 +570,12 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 519 | 570 | dispatch_after(delay, dispatch_get_main_queue(), ^{ |
| 520 | 571 | |
| 521 | 572 | if (!_manager.kit.streamerBase.isStreaming) { |
| 522 | - // if (!_streamerBase.isStreaming) { | |
| 523 | 573 | |
| 524 | 574 | if (_logPrintEnable) { |
| 525 | 575 | NSLog(@"CNLiveGPUStreamerKit-->第(%d)次重连/(%d)", (_maxAutoRetry-_autoRetryCnt+1),_maxAutoRetry); |
| 526 | 576 | } |
| 527 | 577 | [CNLiveStreamerTools getRealTimeString:^(NSString *timeString) { |
| 528 | -// [self requestStartStreamer:NULL failure:NULL timeString:timeString]; | |
| 578 | + [self requestStartStreamer:NULL failure:NULL timeString:timeString]; | |
| 529 | 579 | }]; |
| 530 | 580 | |
| 531 | 581 | _autoRetryCnt--; |
| ... | ... | @@ -540,7 +590,6 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 540 | 590 | _retryFailed = NO; |
| 541 | 591 | } |
| 542 | 592 | |
| 543 | -#pragma mark - | |
| 544 | 593 | #pragma mark - KSYMethod |
| 545 | 594 | - (UIView *)preview { |
| 546 | 595 | return (UIView *)_manager.kit.preview; |
| ... | ... | @@ -569,13 +618,13 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 569 | 618 | _retryFailed = NO; |
| 570 | 619 | |
| 571 | 620 | [CNLiveStreamerTools getRealTimeString:^(NSString *timeString) { |
| 572 | -// [self requestStartStreamer:successBlock failure:failureBlock timeString:timeString]; | |
| 621 | + [self requestStartStreamer:successBlock failure:failureBlock timeString:timeString]; | |
| 573 | 622 | }]; |
| 574 | 623 | |
| 575 | 624 | } else { |
| 576 | 625 | |
| 577 | 626 | [CNLiveStreamerTools getRealTimeString:^(NSString *timeString) { |
| 578 | -// [self createActivityWithSuccess:successBlock failure:failureBlock timeString:timeString]; | |
| 627 | + [self createActivityWithSuccess:successBlock failure:failureBlock timeString:timeString]; | |
| 579 | 628 | }]; |
| 580 | 629 | |
| 581 | 630 | } |
| ... | ... | @@ -595,7 +644,7 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 595 | 644 | _hostURL = [NSURL URLWithString:url]; //推流地址 |
| 596 | 645 | |
| 597 | 646 | [CNLiveStreamerTools getRealTimeString:^(NSString *timeString) { |
| 598 | -// [self requestStartStreamer:successBlock failure:failureBlock timeString:timeString]; | |
| 647 | + [self requestStartStreamer:successBlock failure:failureBlock timeString:timeString]; | |
| 599 | 648 | }]; |
| 600 | 649 | } |
| 601 | 650 | |
| ... | ... | @@ -603,7 +652,7 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 603 | 652 | [_manager.kit.streamerBase stopStream]; |
| 604 | 653 | _isRecording = NO; |
| 605 | 654 | [CNLiveStreamerTools getRealTimeString:^(NSString *timeString) { |
| 606 | -// [self requestStopStreamerWithInfo:@"User Pause" timeString:timeString]; | |
| 655 | + [self requestStopStreamerWithInfo:@"User Pause" timeString:timeString]; | |
| 607 | 656 | }]; |
| 608 | 657 | } |
| 609 | 658 | |
| ... | ... | @@ -616,7 +665,7 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 616 | 665 | - (void)stopStream { |
| 617 | 666 | if (_activitySuccess) { |
| 618 | 667 | [CNLiveStreamerTools getRealTimeString:^(NSString *timeString) { |
| 619 | -// [self requestStopStreamerWithInfo:@"" timeString:timeString]; | |
| 668 | + [self requestStopStreamerWithInfo:@"" timeString:timeString]; | |
| 620 | 669 | }]; |
| 621 | 670 | _isRecording = NO; |
| 622 | 671 | [self.socket disconnect]; |
| ... | ... | @@ -640,8 +689,6 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 640 | 689 | - (void)appEnterBackground { |
| 641 | 690 | [_manager.kit appEnterBackground]; |
| 642 | 691 | |
| 643 | - // //进入后台停止采集,避免占用资源 | |
| 644 | - // [_manager.kit.streamerBase stopStream]; | |
| 645 | 692 | } |
| 646 | 693 | |
| 647 | 694 | //回到前台 |
| ... | ... | @@ -672,13 +719,11 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 672 | 719 | _manager.kit.stabilizationMode = stabilizationMode; |
| 673 | 720 | } |
| 674 | 721 | |
| 675 | -#pragma mark - | |
| 676 | 722 | #pragma mark - filters |
| 677 | 723 | - (void)setupFilter:(GPUImageOutput<GPUImageInput> *)filter { |
| 678 | 724 | [_manager.kit setupFilter:filter]; |
| 679 | 725 | } |
| 680 | 726 | |
| 681 | -#pragma mark - | |
| 682 | 727 | #pragma mark - 设置接口参数 |
| 683 | 728 | - (void)setActivityId:(NSString *)activityId { |
| 684 | 729 | _activityId = [NSString stringWithFormat:@"%@", activityId]; |
| ... | ... | @@ -736,11 +781,10 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 736 | 781 | } |
| 737 | 782 | |
| 738 | 783 | #pragma mark - GCDAsyncSocketDelegate |
| 739 | - | |
| 740 | 784 | - (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port { |
| 741 | 785 | self.heartTimer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(checkLongConnectByServe) userInfo:nil repeats:YES]; |
| 742 | 786 | [self checkLongConnectByServe]; |
| 743 | - // NSLog(@"socket -------- 已连接"); | |
| 787 | + | |
| 744 | 788 | } |
| 745 | 789 | |
| 746 | 790 | - (void)checkLongConnectByServe { |
| ... | ... | @@ -751,32 +795,27 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 751 | 795 | longConnect = [NSString stringWithFormat:@"%@#%@#",PLAYER_AppID,_activityId]; |
| 752 | 796 | } |
| 753 | 797 | NSData *data = [longConnect dataUsingEncoding:NSUTF8StringEncoding]; |
| 754 | - // NSLog(@"socket-socket--socket---%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); | |
| 755 | 798 | [self.socket writeData:data withTimeout:-1 tag:1]; |
| 799 | + | |
| 756 | 800 | } |
| 757 | 801 | |
| 758 | 802 | - (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag { |
| 759 | - // NSLog(@"socket:%p didWriteDataWithTag:%ld", sock, tag); | |
| 803 | + | |
| 760 | 804 | } |
| 761 | 805 | |
| 762 | 806 | - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag { |
| 763 | - // NSLog(@"socket:%p didReadData:withTag:%ld", sock, tag); | |
| 764 | - | |
| 765 | - // NSString *httpResponse = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; | |
| 766 | 807 | |
| 767 | - // NSLog(@"HTTP Response:\n%@", httpResponse); | |
| 768 | 808 | |
| 769 | 809 | } |
| 770 | 810 | |
| 771 | 811 | - (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err { |
| 772 | - // NSLog(@"socket-------- 断开连接 %@", err); | |
| 773 | 812 | |
| 774 | 813 | if (_isRecording) { |
| 775 | 814 | |
| 776 | 815 | _isRecording = NO; |
| 777 | 816 | |
| 778 | 817 | if (self.logPrintEnable) { |
| 779 | - NSLog(@"CNLiveGPUStreamerKit-->由于监听心跳未能正常运作而暂时断开推流,reason:%@",err?err.localizedDescription:@"nil"); | |
| 818 | + NSLog(@"CNLiveStreamerKit-->由于监听心跳未能正常运作而暂时断开推流,reason:%@",err?err.localizedDescription:@"nil"); | |
| 780 | 819 | } |
| 781 | 820 | |
| 782 | 821 | [_manager.kit.streamerBase stopStream]; |
| ... | ... | @@ -784,29 +823,27 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 784 | 823 | //如果socket异常断开,发送异常通知 |
| 785 | 824 | _streamErrorCode = CNLiveStreamErrorCode_ABNORMAL; |
| 786 | 825 | _streamState = CNLiveStreamStateError; |
| 787 | - [[NSNotificationCenter defaultCenter] postNotificationName:CNLiveStreamStateDidChangeNotification | |
| 826 | + [[NSNotificationCenter defaultCenter] postNotificationName:CNLiveStreamerStateDidChangeNotification | |
| 788 | 827 | object:nil |
| 789 | 828 | userInfo:nil]; |
| 790 | 829 | |
| 791 | 830 | [CNLiveStreamerTools getRealTimeString:^(NSString *timeString) { |
| 792 | -// [self requestStopStreamerWithInfo:@"CNLiveStreamErrorCode_ABNORMAL_1" timeString:timeString]; | |
| 831 | + [self requestStopStreamerWithInfo:@"CNLiveStreamErrorCode_ABNORMAL_1" timeString:timeString]; | |
| 793 | 832 | }]; |
| 794 | 833 | |
| 795 | 834 | |
| 796 | 835 | //重连失败通知开发者 |
| 797 | 836 | if (_retryFailed && _isCNLiveStreaming) { |
| 798 | 837 | _reconnectStatus = CNLiveReconnectStatusFailed; |
| 799 | - [[NSNotificationCenter defaultCenter] postNotificationName:CNLiveStreamReconnectStatusChangedNotification | |
| 838 | + [[NSNotificationCenter defaultCenter] postNotificationName:CNLiveStreamerReconnectStatusChangedNotification | |
| 800 | 839 | object:nil |
| 801 | 840 | userInfo:nil]; |
| 802 | 841 | [self recoverReconnectConfig]; |
| 803 | 842 | } |
| 804 | 843 | |
| 805 | - // NSLog(@"socketBreak---->autoRetryCnt:%d----initiativeRetry:%@----reteying:%@----retryFailed:%@", _autoRetryCnt, _initiativeRetry ? @"YES" : @"NO", _reteying?@"YES":@"NO", _retryFailed?@"YES":@"NO"); | |
| 806 | - | |
| 807 | 844 | if (_autoRetryCnt>0 && !_initiativeRetry) { |
| 808 | 845 | [self tryReconnect]; |
| 809 | - //NSLog(@"CNLiveStreamerKit-->reconnect ----- socketERROR"); | |
| 846 | + | |
| 810 | 847 | } |
| 811 | 848 | |
| 812 | 849 | } |
| ... | ... | @@ -848,25 +885,20 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 848 | 885 | |
| 849 | 886 | _roomId = [NSString stringWithFormat:@"CNLiveAnchorStatus_%@",contentId]; |
| 850 | 887 | |
| 851 | - // NSLog(@"**********************----roomid %@",_roomId); | |
| 852 | - | |
| 853 | 888 | //加入聊天室 |
| 854 | - [[CNLiveMsgManager sharedCNLiveMsgManager] gatherIfNullCreate:_roomId | |
| 855 | - messageCount:1 | |
| 856 | - success:^(NSString *targetId) { | |
| 857 | - | |
| 858 | - if (result) { | |
| 859 | - result(YES); | |
| 860 | - } | |
| 861 | - | |
| 862 | - } error:^(NSInteger errors, NSString *targetId) { | |
| 863 | - | |
| 864 | - // NSLog(@"***********--加入聊天室失败 ----errors %ld",(long)errors); | |
| 865 | - | |
| 866 | - if (result) { | |
| 867 | - result(NO); | |
| 868 | - } | |
| 869 | - }]; | |
| 889 | + [[CNLiveMsgManager sharedCNLiveMsgManager] gatherIfNullCreate:_roomId messageCount:1 success:^(NSString *targetId) { | |
| 890 | + if (result) { | |
| 891 | + result(YES); | |
| 892 | + | |
| 893 | + } | |
| 894 | + | |
| 895 | + } error:^(NSInteger errors, NSString *targetId) { | |
| 896 | + if (result) { | |
| 897 | + result(NO); | |
| 898 | + | |
| 899 | + } | |
| 900 | + | |
| 901 | + }]; | |
| 870 | 902 | } |
| 871 | 903 | |
| 872 | 904 | - (void)initRCloudNotificationObservers { |
| ... | ... | @@ -874,7 +906,7 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 874 | 906 | if (_registerChatNoti) return; |
| 875 | 907 | |
| 876 | 908 | //接收消息通知 |
| 877 | - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveMessage:) name:MsgToolsStreamReceiveNotification object:nil]; | |
| 909 | + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveMessage:) name:CNLiveStreamerMsgReceiveNotification object:nil]; | |
| 878 | 910 | |
| 879 | 911 | _registerChatNoti = YES; |
| 880 | 912 | |
| ... | ... | @@ -887,6 +919,7 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 887 | 919 | int newValue = [noti.userInfo[@"message"] intValue]; |
| 888 | 920 | |
| 889 | 921 | if (_originalStatus == newValue) return; //如果新收到的状态与上一次状态一样不作处理 |
| 922 | + | |
| 890 | 923 | if (!_originalStatus && newValue == 2) { |
| 891 | 924 | return; |
| 892 | 925 | } |
| ... | ... | @@ -907,20 +940,16 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 907 | 940 | |
| 908 | 941 | _registerChatNoti = NO; |
| 909 | 942 | |
| 910 | - [[NSNotificationCenter defaultCenter] removeObserver:self | |
| 911 | - name:MsgToolsStreamReceiveNotification | |
| 912 | - object:nil]; | |
| 943 | + [[NSNotificationCenter defaultCenter] removeObserver:self name:CNLiveStreamerMsgReceiveNotification object:nil]; | |
| 913 | 944 | |
| 914 | - if ([CNLiveStreamerTools isEmptyString:_roomId]) { | |
| 915 | - return; | |
| 945 | + if (![CNLiveStreamerTools isEmptyString:_roomId]) { | |
| 946 | + [[CNLiveMsgManager sharedCNLiveMsgManager] disperse:_roomId success:^(NSString *targetId) { | |
| 947 | + | |
| 948 | + } error:^(NSInteger errors, NSString *targetId) { | |
| 949 | + | |
| 950 | + }]; | |
| 916 | 951 | } |
| 917 | 952 | |
| 918 | - [[CNLiveMsgManager sharedCNLiveMsgManager] disperse:_roomId success:^(NSString *targetId) { | |
| 919 | - | |
| 920 | - } error:^(NSInteger errors, NSString *targetId) { | |
| 921 | - | |
| 922 | - }]; | |
| 923 | - | |
| 924 | 953 | } |
| 925 | 954 | |
| 926 | 955 | #pragma mark - getter |
| ... | ... | @@ -961,30 +990,9 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 961 | 990 | |
| 962 | 991 | #pragma mark - dealloc |
| 963 | 992 | - (void)dealloc { |
| 964 | - | |
| 965 | - [[NSNotificationCenter defaultCenter] removeObserver:self | |
| 966 | - name:KSYCaptureStateDidChangeNotification | |
| 967 | - object:nil]; | |
| 968 | - | |
| 969 | - [[NSNotificationCenter defaultCenter] removeObserver:self | |
| 970 | - name:KSYStreamStateDidChangeNotification | |
| 971 | - object:nil]; | |
| 972 | - | |
| 973 | - [[NSNotificationCenter defaultCenter] removeObserver:self | |
| 974 | - name:UIApplicationDidEnterBackgroundNotification | |
| 975 | - object:nil]; | |
| 976 | - | |
| 977 | - [[NSNotificationCenter defaultCenter] removeObserver:self | |
| 978 | - name:UIApplicationWillEnterForegroundNotification | |
| 979 | - object:nil]; | |
| 980 | - | |
| 981 | - [[NSNotificationCenter defaultCenter] removeObserver:self | |
| 982 | - name:MsgToolsStreamReceiveNotification | |
| 983 | - object:nil]; | |
| 984 | - | |
| 993 | + [[NSNotificationCenter defaultCenter] removeObserver:self]; | |
| 985 | 994 | [UIApplication sharedApplication].idleTimerDisabled = NO; |
| 986 | 995 | |
| 987 | - | |
| 988 | 996 | [_manager destroyStreamerManager]; |
| 989 | 997 | _manager = nil; |
| 990 | 998 | } |
| ... | ... | @@ -998,4 +1006,375 @@ NSString * const CNLiveServiceConnectBreakNotification = @"CNLiveServiceConnectB |
| 998 | 1006 | return view; |
| 999 | 1007 | } |
| 1000 | 1008 | |
| 1009 | +#pragma mark - data | |
| 1010 | +- (void)requestCreateActivityParameter:(NSDictionary *)param success:(void(^)(void))successBlock failure :(void (^)(NSDictionary *errorDic))failureBlock { | |
| 1011 | + | |
| 1012 | + [CNLivePlayerNetworkManager POST:StreamerURL parameters:param success:^(NSURLResponse * _Nullable response, id _Nullable responseObject) { | |
| 1013 | + | |
| 1014 | + if (![CNLiveStreamerTools isEmptyString:responseObject[@"errorCode"]] && [responseObject[@"errorCode"] intValue] == 0) { | |
| 1015 | + | |
| 1016 | + if (self.logPrintEnable) { | |
| 1017 | + NSLog(@"CNLiveGPUStreamerKit-->创建活动成功"); | |
| 1018 | + } | |
| 1019 | + | |
| 1020 | + //创建活动成功后,连接RM,获取主播状态 | |
| 1021 | + // [self initRCloudWithAppId:SHARE_APPID appKey:SHARE_APPKEY connectResult:NULL]; | |
| 1022 | + | |
| 1023 | + _activitySuccess = YES; | |
| 1024 | + | |
| 1025 | + NSString *url = responseObject[@"data"][@"location"]; | |
| 1026 | + _hostURL = [NSURL URLWithString:url]; | |
| 1027 | + | |
| 1028 | + [CNLiveStreamerTools getRealTimeString:^(NSString *timeString) { | |
| 1029 | + [self requestStartStreamer:successBlock failure:failureBlock timeString:timeString]; | |
| 1030 | + }]; | |
| 1031 | + | |
| 1032 | + } else { | |
| 1033 | + | |
| 1034 | + if (self.logPrintEnable) { | |
| 1035 | + NSLog(@"CNLiveGPUStreamerKit-->创建活动失败,失败原因:%@", responseObject); | |
| 1036 | + } | |
| 1037 | + | |
| 1038 | + failureBlock ? failureBlock(responseObject) : nil; | |
| 1039 | + | |
| 1040 | + //用于探针 | |
| 1041 | + | |
| 1042 | + NSError *error = [CNLiveStreamerTools customErrorWithResponseObject:responseObject errorInfo:@"开启推流失败,请重试"]; | |
| 1043 | + | |
| 1044 | + [CNLiveStreamerTools errorStat:error.userInfo.description activityId:_activityId]; | |
| 1045 | + } | |
| 1046 | + | |
| 1047 | + } failure:^(NSURLResponse * _Nullable response, NSError * _Nullable error) { | |
| 1048 | + | |
| 1049 | + NSDictionary *errorDic = @{@"errorCode": [NSString stringWithFormat:@"%ld", error.code], | |
| 1050 | + @"errorMessage": error.localizedDescription}; | |
| 1051 | + | |
| 1052 | + failureBlock ? failureBlock(errorDic) : nil; | |
| 1053 | + | |
| 1054 | + if (self.logPrintEnable) { | |
| 1055 | + NSLog(@"CNLiveGPUStreamerKit-->创建活动失败,失败原因:%@", errorDic); | |
| 1056 | + } | |
| 1057 | + | |
| 1058 | + [CNLiveStreamerTools errorStat:error.userInfo.description activityId:_activityId]; | |
| 1059 | + | |
| 1060 | + }]; | |
| 1061 | + | |
| 1062 | +} | |
| 1063 | + | |
| 1064 | +//启动直播活动 | |
| 1065 | +- (void)requestStartStreamer:(void (^)(void))successBlock failure:(void (^)(NSDictionary *))failureBlock timeString:(NSString *)timeString { | |
| 1066 | + | |
| 1067 | + _reteying = NO; | |
| 1068 | + | |
| 1069 | + // NSDate *date = [NSDate date]; | |
| 1070 | + // NSInteger time = [date timeIntervalSince1970]; | |
| 1071 | + // NSString *timeString = [NSString stringWithFormat:@"%ld", (long)time]; | |
| 1072 | + | |
| 1073 | + NSMutableDictionary *parameter = [@{@"appId": PLAYER_AppID, | |
| 1074 | + @"activityId": _activityId, | |
| 1075 | + @"timestamp":timeString, | |
| 1076 | + @"platform_id":[NSBundle mainBundle].bundleIdentifier} copy] ; | |
| 1077 | + | |
| 1078 | + NSMutableDictionary *para = [CNLiveStreamerTools encryptionSignWithParameter:parameter]; | |
| 1079 | + | |
| 1080 | + [CNLivePlayerNetworkManager GET:StartStreamerURL parameters:para success:^(NSURLResponse * _Nullable response, id _Nullable responseObject) { | |
| 1081 | + | |
| 1082 | + if (responseObject[@"errorCode"] && [responseObject[@"errorCode"]isEqualToString:@"0"]) { //开始活动success | |
| 1083 | + | |
| 1084 | + _isRecording = YES; | |
| 1085 | + BOOL linkResult; | |
| 1086 | + | |
| 1087 | + if (_socket.isDisconnected || !_socket) { | |
| 1088 | + self.socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()]; | |
| 1089 | + NSError *error; | |
| 1090 | + linkResult = [self.socket connectToHost:Host onPort:Port withTimeout:5 error:&error]; | |
| 1091 | + } else { | |
| 1092 | + linkResult = YES; | |
| 1093 | + } | |
| 1094 | + | |
| 1095 | + if (linkResult) { //连接聊天室success | |
| 1096 | + | |
| 1097 | + if (_manager.kit.streamerBase.isStreaming) { | |
| 1098 | + _streamState = CNLiveStreamStateConnected; | |
| 1099 | + [[NSNotificationCenter defaultCenter] postNotificationName:CNLiveStreamerStateDidChangeNotification | |
| 1100 | + object:nil | |
| 1101 | + userInfo:nil]; | |
| 1102 | + } | |
| 1103 | + | |
| 1104 | + if (!_manager.kit.streamerBase.isStreaming) { | |
| 1105 | + [_manager.kit.streamerBase startStream:_hostURL]; | |
| 1106 | + } | |
| 1107 | + | |
| 1108 | + | |
| 1109 | + if (successBlock) { | |
| 1110 | + successBlock(); | |
| 1111 | + } | |
| 1112 | + | |
| 1113 | + if (self.logPrintEnable) { | |
| 1114 | + // D_NSLog(@"CNLiveGPUStreamerKit-->开启活动成功 -----连接状态%@", share.kit.streamerBase.isStreaming ? @"YES" : @"NO"); | |
| 1115 | + NSLog(@"CNLiveGPUStreamerKit-->开启活动成功"); | |
| 1116 | + } | |
| 1117 | + | |
| 1118 | + _initiativeRetry = NO; | |
| 1119 | + | |
| 1120 | + | |
| 1121 | + } else { //连接聊天室fail | |
| 1122 | + | |
| 1123 | + _isRecording = NO; | |
| 1124 | + | |
| 1125 | + /** | |
| 1126 | + * 开始活动成功但是聊天室连接失败应将活动状态置为“-2” | |
| 1127 | + */ | |
| 1128 | + [CNLiveStreamerTools getRealTimeString:^(NSString *timeString) { | |
| 1129 | + [self requestStopStreamerWithInfo:@"CNLiveStreamErrorCode_JoinRoomFailed" timeString:timeString]; | |
| 1130 | + }]; | |
| 1131 | + | |
| 1132 | + /** | |
| 1133 | + * 若返回前台,流没断,但是连接聊天室失败,需将流断开 | |
| 1134 | + */ | |
| 1135 | + if (_manager.kit.streamerBase.isStreaming) { | |
| 1136 | + [_manager.kit.streamerBase stopStream]; | |
| 1137 | + } | |
| 1138 | + | |
| 1139 | + //用于错误探针 | |
| 1140 | + NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"socket连接失败"}]; | |
| 1141 | + | |
| 1142 | + [CNLiveStreamerTools errorStat:error.userInfo.description activityId:_activityId]; | |
| 1143 | + | |
| 1144 | + //用于回调 | |
| 1145 | + NSDictionary *errorDic = @{@"errorCode": @"-1", | |
| 1146 | + @"errorMessage": @"心跳连接失败,请重试"}; | |
| 1147 | + | |
| 1148 | + if (self.logPrintEnable) { | |
| 1149 | + NSLog(@"CNLiveGPUStreamerKit-->开启活动失败,失败原因:%@", errorDic); | |
| 1150 | + } | |
| 1151 | + | |
| 1152 | + //重连失败通知开发者 | |
| 1153 | + if (_retryFailed && _isCNLiveStreaming) { | |
| 1154 | + _reconnectStatus = CNLiveReconnectStatusFailed; | |
| 1155 | + [[NSNotificationCenter defaultCenter] postNotificationName:CNLiveStreamerReconnectStatusChangedNotification | |
| 1156 | + object:nil | |
| 1157 | + userInfo:nil]; | |
| 1158 | + [self recoverReconnectConfig]; | |
| 1159 | + } | |
| 1160 | + | |
| 1161 | + // NSLog(@"socketConnectFailed---->autoRetryCnt:%d----initiativeRetry:%@----reteying:%@----retryFailed:%@", _autoRetryCnt, _initiativeRetry ? @"YES" : @"NO", _reteying?@"YES":@"NO", _retryFailed?@"YES":@"NO"); | |
| 1162 | + | |
| 1163 | + if (_autoRetryCnt>0 && !_initiativeRetry) { | |
| 1164 | + [self tryReconnect]; | |
| 1165 | + // D_NSLog(@"CNLiveGPUStreamerKit-->reconnect ----- socket连接失败"); | |
| 1166 | + | |
| 1167 | + } | |
| 1168 | + | |
| 1169 | + failureBlock ? failureBlock(errorDic) : nil; | |
| 1170 | + | |
| 1171 | + } | |
| 1172 | + | |
| 1173 | + } else { //开始活动失败 | |
| 1174 | + | |
| 1175 | + _isRecording = NO; | |
| 1176 | + | |
| 1177 | + if (_manager.kit.streamerBase.isStreaming) { | |
| 1178 | + [_manager.kit.streamerBase stopStream]; | |
| 1179 | + } | |
| 1180 | + | |
| 1181 | + //用于探针 | |
| 1182 | + NSError *error = [CNLiveStreamerTools customErrorWithResponseObject:responseObject errorInfo:@"开启推流失败,请重试"]; | |
| 1183 | + | |
| 1184 | + [CNLiveStreamerTools errorStat:error.userInfo.description activityId:_activityId]; | |
| 1185 | + | |
| 1186 | + if (self.logPrintEnable) { | |
| 1187 | + NSLog(@"CNLiveGPUStreamerKit-->开启活动失败,失败原因:%@", responseObject); | |
| 1188 | + } | |
| 1189 | + | |
| 1190 | + //重连失败通知开发者 | |
| 1191 | + if (_retryFailed && _isCNLiveStreaming) { | |
| 1192 | + _reconnectStatus = CNLiveReconnectStatusFailed; | |
| 1193 | + [[NSNotificationCenter defaultCenter] postNotificationName:CNLiveStreamerReconnectStatusChangedNotification | |
| 1194 | + object:nil | |
| 1195 | + userInfo:nil]; | |
| 1196 | + [self recoverReconnectConfig]; | |
| 1197 | + } | |
| 1198 | + | |
| 1199 | + // NSLog(@"startFailed---->autoRetryCnt:%d----initiativeRetry:%@----reteying:%@----retryFailed:%@", _autoRetryCnt, _initiativeRetry ? @"YES" : @"NO", _reteying?@"YES":@"NO", _retryFailed?@"YES":@"NO"); | |
| 1200 | + | |
| 1201 | + if (_autoRetryCnt>0 && !_initiativeRetry) { | |
| 1202 | + [self tryReconnect]; | |
| 1203 | + // D_NSLog(@"CNLiveGPUStreamerKit-->reconnect ----- 启动活动失败"); | |
| 1204 | + } | |
| 1205 | + | |
| 1206 | + failureBlock ? failureBlock(responseObject) : nil; | |
| 1207 | + | |
| 1208 | + } | |
| 1209 | + | |
| 1210 | + } failure:^(NSURLResponse * _Nullable response, NSError * _Nullable error) { | |
| 1211 | + | |
| 1212 | + _isRecording = NO; | |
| 1213 | + | |
| 1214 | + if (_manager.kit.streamerBase.isStreaming) { | |
| 1215 | + [_manager.kit.streamerBase stopStream]; | |
| 1216 | + } | |
| 1217 | + | |
| 1218 | + NSDictionary *errorDic = @{@"errorCode": [NSString stringWithFormat:@"%ld",error.code], @"errorMessage": error.localizedDescription}; | |
| 1219 | + | |
| 1220 | + [CNLiveStreamerTools errorStat:error.userInfo.description activityId:_activityId]; | |
| 1221 | + | |
| 1222 | + | |
| 1223 | + if (self.logPrintEnable) { | |
| 1224 | + NSLog(@"CNLiveGPUStreamerKit-->开启活动失败,失败原因:%@", errorDic); | |
| 1225 | + } | |
| 1226 | + | |
| 1227 | + //重连失败通知开发者 | |
| 1228 | + if (_retryFailed && _isCNLiveStreaming) { | |
| 1229 | + _reconnectStatus = CNLiveReconnectStatusFailed; | |
| 1230 | + [[NSNotificationCenter defaultCenter] postNotificationName:CNLiveStreamerReconnectStatusChangedNotification | |
| 1231 | + object:nil | |
| 1232 | + userInfo:nil]; | |
| 1233 | + [self recoverReconnectConfig]; | |
| 1234 | + } | |
| 1235 | + | |
| 1236 | + // NSLog(@"no wlan---->autoRetryCnt:%d----initiativeRetry:%@----reteying:%@----retryFailed:%@", _autoRetryCnt, _initiativeRetry ? @"YES" : @"NO", _reteying?@"YES":@"NO", _retryFailed?@"YES":@"NO"); | |
| 1237 | + | |
| 1238 | + if (_autoRetryCnt>0 && !_initiativeRetry) { | |
| 1239 | + [self tryReconnect]; | |
| 1240 | + // D_NSLog(@"CNLiveGPUStreamerKit-->reconnect ----- 启动活动(((请求)))失败"); | |
| 1241 | + } | |
| 1242 | + | |
| 1243 | + failureBlock ? failureBlock(errorDic) : nil; | |
| 1244 | + | |
| 1245 | + }]; | |
| 1246 | +} | |
| 1247 | + | |
| 1248 | +//结束直播活动 | |
| 1249 | +- (void)requestStopStreamerWithInfo:(NSString *)remark timeString:(NSString *)timeString { | |
| 1250 | + // NSDate *date = [NSDate date]; | |
| 1251 | + // NSInteger time = [date timeIntervalSince1970]; | |
| 1252 | + // NSString *timeString = [NSString stringWithFormat:@"%ld", (long)time]; | |
| 1253 | + | |
| 1254 | + NSMutableDictionary *parameter = [@{@"appId": PLAYER_AppID, | |
| 1255 | + @"activityId": _activityId, | |
| 1256 | + @"platform_id":[NSBundle mainBundle].bundleIdentifier, | |
| 1257 | + @"timestamp":timeString} mutableCopy]; | |
| 1258 | + if (remark.length > 0) { | |
| 1259 | + [parameter setObject:remark forKey:@"remark"]; | |
| 1260 | + } | |
| 1261 | + | |
| 1262 | + NSMutableDictionary *para = [CNLiveStreamerTools encryptionSignWithParameter:parameter]; | |
| 1263 | + | |
| 1264 | + [CNLivePlayerNetworkManager GET:StopStreamerURL parameters:para success:^(NSURLResponse * _Nullable response, id _Nullable responseObject) { | |
| 1265 | + | |
| 1266 | + if ([[NSString stringWithFormat:@"%@", responseObject[@"errorCode"]] isEqualToString:@"0"]) { | |
| 1267 | + | |
| 1268 | + if (self.logPrintEnable) { | |
| 1269 | + if (remark.length > 0) { | |
| 1270 | + NSLog(@"CNLiveGPUStreamerKit-->异常结束推流error:%@,并成功通知后台", remark); | |
| 1271 | + } else { | |
| 1272 | + //结束推流成功通知 | |
| 1273 | + _streamState = CNLiveStopStreamSuccess; | |
| 1274 | + [[NSNotificationCenter defaultCenter] postNotificationName:CNLiveStreamerStateDidChangeNotification | |
| 1275 | + object:nil | |
| 1276 | + userInfo:nil]; | |
| 1277 | + | |
| 1278 | + NSLog(@"CNLiveGPUStreamerKit-->正常结束推流并成功通知后台"); | |
| 1279 | + } | |
| 1280 | + } | |
| 1281 | + | |
| 1282 | + | |
| 1283 | + if ([CNLiveStreamerTools isEmptyString:remark]) { | |
| 1284 | + NSString *duration = responseObject[@"data"][@"duration"]; | |
| 1285 | + if ([duration isKindOfClass:[NSString class]] && duration.length > 0) { | |
| 1286 | + [[NSNotificationCenter defaultCenter] postNotificationName:CNLiveStreamerGetDurationNotification object:duration ? duration : @"0"]; | |
| 1287 | + } else { | |
| 1288 | + [[NSNotificationCenter defaultCenter] postNotificationName:CNLiveStreamerGetDurationNotification object:@"0"]; | |
| 1289 | + } | |
| 1290 | + } | |
| 1291 | + | |
| 1292 | + | |
| 1293 | + } else { | |
| 1294 | + | |
| 1295 | + if ([CNLiveStreamerTools isEmptyString:remark]) { | |
| 1296 | + [[NSNotificationCenter defaultCenter] postNotificationName:CNLiveStreamerGetDurationNotification object:@"0"]; | |
| 1297 | + | |
| 1298 | + } | |
| 1299 | + | |
| 1300 | + if (self.logPrintEnable) { | |
| 1301 | + if (remark.length > 0) { | |
| 1302 | + NSLog(@"CNLiveGPUStreamerKit-->异常结束推流error:%@,未能通知后台 %@", remark,responseObject); | |
| 1303 | + } else { | |
| 1304 | + NSLog(@"CNLiveGPUStreamerKit-->正常结束推流,未能通知后台 %@",responseObject); | |
| 1305 | + //结束推流失败通知 | |
| 1306 | + _streamState = CNLiveStopStreamFailure; | |
| 1307 | + [[NSNotificationCenter defaultCenter] postNotificationName:CNLiveStreamerStateDidChangeNotification | |
| 1308 | + object:nil | |
| 1309 | + userInfo:nil]; | |
| 1310 | + } | |
| 1311 | + } | |
| 1312 | + | |
| 1313 | + | |
| 1314 | + NSError *error = [CNLiveStreamerTools customErrorWithResponseObject:responseObject errorInfo:@"结束推流失败"]; | |
| 1315 | + | |
| 1316 | + [CNLiveStreamerTools errorStat:error.userInfo.description activityId:_activityId]; | |
| 1317 | + | |
| 1318 | + } | |
| 1319 | + | |
| 1320 | + } failure:^(NSURLResponse * _Nullable response, NSError * _Nullable error) { | |
| 1321 | + | |
| 1322 | + if (self.logPrintEnable) { | |
| 1323 | + if (remark.length > 0) { | |
| 1324 | + NSLog(@"CNLiveGPUStreamerKit-->异常结束推流error:%@,未能通知后台", remark); | |
| 1325 | + } else { | |
| 1326 | + NSLog(@"CNLiveGPUStreamerKit-->正常结束推流,未能通知后台"); | |
| 1327 | + } | |
| 1328 | + } | |
| 1329 | + | |
| 1330 | + //结束推流失败通知 | |
| 1331 | + _streamState = CNLiveStopStreamFailure; | |
| 1332 | + [[NSNotificationCenter defaultCenter] postNotificationName:CNLiveStreamerStateDidChangeNotification | |
| 1333 | + object:nil | |
| 1334 | + userInfo:nil]; | |
| 1335 | + | |
| 1336 | + [CNLiveStreamerTools errorStat:error.userInfo.description activityId:_activityId]; | |
| 1337 | + | |
| 1338 | + }]; | |
| 1339 | +} | |
| 1340 | + | |
| 1341 | +//创建直播活动 | |
| 1342 | +- (void)createActivityWithSuccess:(void (^)(void))successBlock failure:(void (^)(NSDictionary *))failureBlock timeString:(NSString *)timeString { | |
| 1343 | + //如果不是纯音频推流,先判断是否已开启采集状态,若未开启直接返回 | |
| 1344 | + if (!_pureAudioMode) { | |
| 1345 | + if (_manager.kit.captureState != KSYCaptureStateCapturing) { | |
| 1346 | + | |
| 1347 | + NSDictionary *errorDic = @{@"errorCode": @"-101", | |
| 1348 | + @"errorMessage": @"未开启采集状态"}; | |
| 1349 | + | |
| 1350 | + failureBlock ? failureBlock(errorDic) : nil; | |
| 1351 | + return; | |
| 1352 | + } | |
| 1353 | + } | |
| 1354 | + | |
| 1355 | + NSDate *date = [NSDate date]; | |
| 1356 | +// NSInteger time = [date timeIntervalSince1970]; | |
| 1357 | +// NSString *timeString = [NSString stringWithFormat:@"%ld", (long)time]; | |
| 1358 | + | |
| 1359 | + NSDictionary *params=@{@"platform_id":[NSBundle mainBundle].bundleIdentifier, | |
| 1360 | + @"timestamp": timeString, | |
| 1361 | + @"appId": PLAYER_AppID, | |
| 1362 | + @"isHorizontalScreen":[NSString stringWithFormat:@"%d",_isHorizontalScreen], | |
| 1363 | + @"uuid":[CNLiveStreamerTools getUidForStat:date]}; | |
| 1364 | + | |
| 1365 | + [_parameter addEntriesFromDictionary:params]; | |
| 1366 | + | |
| 1367 | + //避免创建活动失败,再次创建时字典中包含已加密sign | |
| 1368 | + [_parameter removeObjectForKey:@"sign"]; | |
| 1369 | + | |
| 1370 | + //加密参数 | |
| 1371 | + NSMutableDictionary *para = [CNLiveStreamerTools encryptionSignWithParameter:_parameter]; | |
| 1372 | + | |
| 1373 | + [self requestCreateActivityParameter:para success:successBlock failure:failureBlock]; | |
| 1374 | + | |
| 1375 | + [CNLiveStreamerTools statSDKWithDate:date activityId:_activityId]; | |
| 1376 | + | |
| 1377 | +} | |
| 1378 | + | |
| 1379 | + | |
| 1001 | 1380 | @end | ... | ... |
CNLivePlayer/Classes/Streamer/CNLiveStreamerTools.m
| ... | ... | @@ -13,7 +13,7 @@ |
| 13 | 13 | #import "CNLivePlayerUrl.h" |
| 14 | 14 | |
| 15 | 15 | @implementation CNLiveStreamerTools |
| 16 | - | |
| 16 | +#pragma mark - 加密 | |
| 17 | 17 | + (NSMutableDictionary *)encryptionSignWithParameter:(NSMutableDictionary *)parameter { |
| 18 | 18 | NSString *string = [NSString stringWithFormat:@"%@&key=%@",[self signvalue:parameter],PLAYER_AppKey]; |
| 19 | 19 | NSString *signString = [[self sha1:string] uppercaseString]; |
| ... | ... | @@ -22,10 +22,7 @@ |
| 22 | 22 | return startPara; |
| 23 | 23 | } |
| 24 | 24 | |
| 25 | -#pragma mark - | |
| 26 | -#pragma mark - 加密 | |
| 27 | -+ (NSString*)sha1:(NSString *)string | |
| 28 | -{ | |
| 25 | ++ (NSString*)sha1:(NSString *)string { | |
| 29 | 26 | NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding]; |
| 30 | 27 | |
| 31 | 28 | uint8_t digest[CC_SHA1_DIGEST_LENGTH]; |
| ... | ... | @@ -44,8 +41,7 @@ |
| 44 | 41 | return output; |
| 45 | 42 | } |
| 46 | 43 | |
| 47 | -+ (NSString *)signvalue:(NSDictionary*)parameter | |
| 48 | -{ | |
| 44 | ++ (NSString *)signvalue:(NSDictionary*)parameter { | |
| 49 | 45 | //对所有传入参数按照字段名的 ASCII 码从小到大排序 |
| 50 | 46 | NSArray *keyArr=[parameter allKeys]; |
| 51 | 47 | NSArray *arr = [keyArr sortedArrayUsingSelector:@selector(compare:)]; |
| ... | ... | @@ -66,10 +62,8 @@ |
| 66 | 62 | return string1; |
| 67 | 63 | } |
| 68 | 64 | |
| 69 | -#pragma mark - | |
| 70 | 65 | #pragma mark - 探针 |
| 71 | -+ (void)statSDKWithDate:(NSDate *)date activityId:(NSString *)activityId | |
| 72 | -{ | |
| 66 | ++ (void)statSDKWithDate:(NSDate *)date activityId:(NSString *)activityId { | |
| 73 | 67 | [CNLiveStreamerTools getRealTimeString:^(NSString *timeString) { |
| 74 | 68 | NSString *stamp = [NSString stringWithFormat:@"%.3f", [timeString floatValue]]; |
| 75 | 69 | stamp = [stamp stringByReplacingOccurrencesOfString:@"." withString:@""]; |
| ... | ... | @@ -79,8 +73,7 @@ |
| 79 | 73 | |
| 80 | 74 | } |
| 81 | 75 | |
| 82 | -+ (void)errorStat:(NSString *)errorString activityId:(NSString *)activityId | |
| 83 | -{ | |
| 76 | ++ (void)errorStat:(NSString *)errorString activityId:(NSString *)activityId { | |
| 84 | 77 | __block NSString *errorStr; |
| 85 | 78 | [CNLiveStreamerTools getRealTimeString:^(NSString *timeString) { |
| 86 | 79 | errorStr = [self urlEncodeUsingEncodingString:errorString]; |
| ... | ... | @@ -101,7 +94,6 @@ |
| 101 | 94 | CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding)); |
| 102 | 95 | } |
| 103 | 96 | |
| 104 | -#pragma mark - | |
| 105 | 97 | #pragma mark - uuid |
| 106 | 98 | + (NSString *)getUidForStat:(NSDate *)date { |
| 107 | 99 | NSString *uid = @""; |
| ... | ... | @@ -138,10 +130,7 @@ |
| 138 | 130 | uid = [[defauts objectForKey:@"kCNLiveUserDefaultsUIDKey"] copy]; |
| 139 | 131 | return uid; |
| 140 | 132 | } else { |
| 141 | - | |
| 142 | - // NSString *stamp = [NSString stringWithFormat:@"%.3f", [date timeIntervalSince1970]]; | |
| 143 | - // stamp = [stamp stringByReplacingOccurrencesOfString:@"." withString:@""]; | |
| 144 | - | |
| 133 | + | |
| 145 | 134 | NSString *idfv = [[[[UIDevice currentDevice] identifierForVendor] UUIDString] stringByReplacingOccurrencesOfString:@"-" withString:@""]; |
| 146 | 135 | uid = [NSString stringWithFormat:@"%@_%@", idfv, date]; |
| 147 | 136 | |
| ... | ... | @@ -153,8 +142,7 @@ |
| 153 | 142 | } |
| 154 | 143 | |
| 155 | 144 | //错误信息 |
| 156 | -+ (NSError *)customErrorWithResponseObject:(id)responseObject errorInfo:(NSString *) errorInfo | |
| 157 | -{ | |
| 145 | ++ (NSError *)customErrorWithResponseObject:(id)responseObject errorInfo:(NSString *) errorInfo { | |
| 158 | 146 | //用于探针 |
| 159 | 147 | NSString *defaultErrorInfo; |
| 160 | 148 | NSInteger errorCode = -1; |
| ... | ... | @@ -170,50 +158,18 @@ |
| 170 | 158 | } |
| 171 | 159 | |
| 172 | 160 | |
| 173 | -+ (BOOL)isEmptyString:(NSString *)string | |
| 174 | -{ | |
| 161 | ++ (BOOL)isEmptyString:(NSString *)string { | |
| 175 | 162 | if (!string || ![string isKindOfClass:[NSString class]] || string.length == 0 || [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]].length == 0) { |
| 176 | 163 | return YES; |
| 177 | 164 | } |
| 178 | 165 | return NO; |
| 179 | 166 | } |
| 180 | 167 | |
| 181 | -#pragma mark - | |
| 182 | 168 | #pragma mark - 真时时间 |
| 183 | -+ (void)getRealTimeString:(void (^)(NSString * __nullable))realTime | |
| 184 | -{ | |
| 169 | ++ (void)getRealTimeString:(void (^)(NSString * __nullable))realTime { | |
| 185 | 170 | NSInteger time = [[NSDate date] timeIntervalSince1970]; |
| 186 | 171 | NSString *timeString = [NSString stringWithFormat:@"%ld", (long)time]; |
| 187 | 172 | realTime(timeString); |
| 188 | - | |
| 189 | - // [NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:HTTPorHTTPs@"api.cnlive.com/open/api2/timestamp"]] queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {// https://m.baidu.com | |
| 190 | - // | |
| 191 | - // if (!response) { | |
| 192 | - // NSInteger time = [[NSDate date] timeIntervalSince1970]; | |
| 193 | - // NSString *timeString = [NSString stringWithFormat:@"%ld", (long)time]; | |
| 194 | - // dispatch_sync(dispatch_get_main_queue(), ^{ | |
| 195 | - // realTime(timeString); | |
| 196 | - // }); | |
| 197 | - // return ; | |
| 198 | - // } | |
| 199 | - // | |
| 200 | - // NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; | |
| 201 | - // NSString *timestamp = [[httpResponse allHeaderFields] objectForKey:@"Date"]; | |
| 202 | - // | |
| 203 | - // NSString *timeStr = [timestamp substringWithRange:NSMakeRange(5, 20)]; | |
| 204 | - // NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; | |
| 205 | - // NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:@"GMT"]; | |
| 206 | - // NSLocale *local = [[NSLocale alloc]initWithLocaleIdentifier:@"en_US_POSIX"]; | |
| 207 | - // [formatter setLocale:local];//需要配置区域,不然会造成模拟器正常,真机日期为null的情况 | |
| 208 | - // [formatter setTimeZone:timeZone]; | |
| 209 | - // [formatter setDateFormat:@"dd MMM yyyy HH:mm:ss"];//设置源时间字符串的格式 | |
| 210 | - // NSDate *date = [formatter dateFromString:timeStr];//将源时间字符串转化为NSDate | |
| 211 | - // | |
| 212 | - // NSString *timeString = [NSString stringWithFormat:@"%.0f", [date timeIntervalSince1970]]; | |
| 213 | - // dispatch_sync(dispatch_get_main_queue(), ^{ | |
| 214 | - // realTime(timeString); | |
| 215 | - // }); | |
| 216 | - // }]; | |
| 217 | 173 | } |
| 218 | 174 | |
| 219 | 175 | @end | ... | ... |
CNLivePlayer/Classes/Streamer/CNLiveStreamerUrl.h
0 → 100644
| 1 | +// | |
| 2 | +// CNLiveStreamerUrl.h | |
| 3 | +// CNLivePlayer | |
| 4 | +// | |
| 5 | +// Created by CNLive-zxw on 2019/8/14. | |
| 6 | +// Copyright © 2019 153993236@qq.com. All rights reserved. | |
| 7 | +// | |
| 8 | + | |
| 9 | +#ifndef CNLiveStreamerUrl_h | |
| 10 | +#define CNLiveStreamerUrl_h | |
| 11 | + | |
| 12 | +#import "CNLivePlayerManager.h" | |
| 13 | + | |
| 14 | +#pragma mark - 推流器版本号 | |
| 15 | +#define StreamerSDKVersion @"0.0.1" | |
| 16 | + | |
| 17 | +#pragma mark - 推流 | |
| 18 | +//创建直播活动 | |
| 19 | +#define StreamerURL [NSString stringWithFormat:@"%@/live_epg/createActivity", [CNLivePlayerManager manager].isTestEnvironment ? @"http://test.open.cnlive.com/openapi/api2" : @"http://api.cnlive.com/open/api2"] | |
| 20 | + | |
| 21 | +//启动直播活动 | |
| 22 | +#define StartStreamerURL [NSString stringWithFormat:@"%@/live_epg/startActivity", [CNLivePlayerManager manager].isTestEnvironment ? @"http://test.open.cnlive.com/openapi/api2" : @"http://api.cnlive.com/open/api2"] | |
| 23 | + | |
| 24 | +//停止直播活动 | |
| 25 | +#define StopStreamerURL [NSString stringWithFormat:@"%@/live_epg/stopActivity", [CNLivePlayerManager manager].isTestEnvironment ? @"http://test.open.cnlive.com/openapi/api2" : @"http://api.cnlive.com/open/api2"] | |
| 26 | + | |
| 27 | +#endif /* CNLiveStreamerUrl_h */ | ... | ... |
Example/CNLivePlayer.xcodeproj/project.pbxproj
| ... | ... | @@ -7,13 +7,23 @@ |
| 7 | 7 | objects = { |
| 8 | 8 | |
| 9 | 9 | /* Begin PBXBuildFile section */ |
| 10 | - 0807DF0E230799E000F409AC /* CNLivePlayerController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0807DF0D230799E000F409AC /* CNLivePlayerController.m */; }; | |
| 11 | - 085FA988230D34890072B936 /* CNLiveStreamerController.m in Sources */ = {isa = PBXBuildFile; fileRef = 085FA987230D34890072B936 /* CNLiveStreamerController.m */; }; | |
| 12 | 10 | 086413BC22EAE229008713D3 /* VideoToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 086413BB22EAE229008713D3 /* VideoToolbox.framework */; }; |
| 13 | 11 | 086413BE22EAE23E008713D3 /* libbz2.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 086413BD22EAE23E008713D3 /* libbz2.tbd */; }; |
| 14 | 12 | 086413C022EAE24F008713D3 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 086413BF22EAE24F008713D3 /* libz.tbd */; }; |
| 15 | 13 | 086413C222EAE591008713D3 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 086413C122EAE591008713D3 /* OpenGLES.framework */; }; |
| 16 | 14 | 086413C422EAEC11008713D3 /* libstdc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 086413C322EAEC11008713D3 /* libstdc++.tbd */; }; |
| 15 | + 08740E51230E7DFB00B5D28D /* CNLiveStreamerController.m in Sources */ = {isa = PBXBuildFile; fileRef = 08740E3F230E7DFA00B5D28D /* CNLiveStreamerController.m */; }; | |
| 16 | + 08740E52230E7DFB00B5D28D /* StreamerDetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 08740E40230E7DFA00B5D28D /* StreamerDetailViewController.m */; }; | |
| 17 | + 08740E53230E7DFB00B5D28D /* FilterFunctionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 08740E41230E7DFA00B5D28D /* FilterFunctionView.m */; }; | |
| 18 | + 08740E54230E7DFB00B5D28D /* SliderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 08740E44230E7DFA00B5D28D /* SliderView.m */; }; | |
| 19 | + 08740E55230E7DFB00B5D28D /* FloatingViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 08740E45230E7DFA00B5D28D /* FloatingViewController.m */; }; | |
| 20 | + 08740E56230E7DFB00B5D28D /* AudioStreamingViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 08740E46230E7DFA00B5D28D /* AudioStreamingViewController.m */; }; | |
| 21 | + 08740E57230E7DFB00B5D28D /* MoreFunctionsView.m in Sources */ = {isa = PBXBuildFile; fileRef = 08740E47230E7DFA00B5D28D /* MoreFunctionsView.m */; }; | |
| 22 | + 08740E58230E7DFB00B5D28D /* AudioCfgView.m in Sources */ = {isa = PBXBuildFile; fileRef = 08740E48230E7DFA00B5D28D /* AudioCfgView.m */; }; | |
| 23 | + 08740E59230E7DFB00B5D28D /* BgmPlayerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 08740E4D230E7DFA00B5D28D /* BgmPlayerView.m */; }; | |
| 24 | + 08740E5C230E83B100B5D28D /* LoadingView.m in Sources */ = {isa = PBXBuildFile; fileRef = 08740E5B230E83B100B5D28D /* LoadingView.m */; }; | |
| 25 | + 08740E5E230E8A0700B5D28D /* house.gif in Resources */ = {isa = PBXBuildFile; fileRef = 08740E5D230E8A0700B5D28D /* house.gif */; }; | |
| 26 | + 08740E62230E8C6500B5D28D /* CNLivePlayerController.m in Sources */ = {isa = PBXBuildFile; fileRef = 08740E60230E8C6500B5D28D /* CNLivePlayerController.m */; }; | |
| 17 | 27 | 1D258610626B544AFEEFD2F9 /* Pods_CNLivePlayer_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E14DC7AF4B1116AA5BC01855 /* Pods_CNLivePlayer_Example.framework */; }; |
| 18 | 28 | 2A57832D4B5A8EF9638641C3 /* Pods_CNLivePlayer_Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DDD4ACEE076815DE64A1FE2E /* Pods_CNLivePlayer_Tests.framework */; }; |
| 19 | 29 | 6003F58E195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; }; |
| ... | ... | @@ -44,15 +54,34 @@ |
| 44 | 54 | /* End PBXContainerItemProxy section */ |
| 45 | 55 | |
| 46 | 56 | /* Begin PBXFileReference section */ |
| 47 | - 0807DF0C230799E000F409AC /* CNLivePlayerController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CNLivePlayerController.h; sourceTree = "<group>"; }; | |
| 48 | - 0807DF0D230799E000F409AC /* CNLivePlayerController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CNLivePlayerController.m; sourceTree = "<group>"; }; | |
| 49 | - 085FA986230D34890072B936 /* CNLiveStreamerController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CNLiveStreamerController.h; sourceTree = "<group>"; }; | |
| 50 | - 085FA987230D34890072B936 /* CNLiveStreamerController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CNLiveStreamerController.m; sourceTree = "<group>"; }; | |
| 51 | 57 | 086413BB22EAE229008713D3 /* VideoToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = VideoToolbox.framework; path = System/Library/Frameworks/VideoToolbox.framework; sourceTree = SDKROOT; }; |
| 52 | 58 | 086413BD22EAE23E008713D3 /* libbz2.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libbz2.tbd; path = usr/lib/libbz2.tbd; sourceTree = SDKROOT; }; |
| 53 | 59 | 086413BF22EAE24F008713D3 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; |
| 54 | 60 | 086413C122EAE591008713D3 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; }; |
| 55 | 61 | 086413C322EAEC11008713D3 /* libstdc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libstdc++.tbd"; path = "usr/lib/libstdc++.tbd"; sourceTree = SDKROOT; }; |
| 62 | + 08740E3F230E7DFA00B5D28D /* CNLiveStreamerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CNLiveStreamerController.m; sourceTree = "<group>"; }; | |
| 63 | + 08740E40230E7DFA00B5D28D /* StreamerDetailViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StreamerDetailViewController.m; sourceTree = "<group>"; }; | |
| 64 | + 08740E41230E7DFA00B5D28D /* FilterFunctionView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FilterFunctionView.m; sourceTree = "<group>"; }; | |
| 65 | + 08740E42230E7DFA00B5D28D /* AudioCfgView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioCfgView.h; sourceTree = "<group>"; }; | |
| 66 | + 08740E43230E7DFA00B5D28D /* BgmPlayerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BgmPlayerView.h; sourceTree = "<group>"; }; | |
| 67 | + 08740E44230E7DFA00B5D28D /* SliderView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SliderView.m; sourceTree = "<group>"; }; | |
| 68 | + 08740E45230E7DFA00B5D28D /* FloatingViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FloatingViewController.m; sourceTree = "<group>"; }; | |
| 69 | + 08740E46230E7DFA00B5D28D /* AudioStreamingViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AudioStreamingViewController.m; sourceTree = "<group>"; }; | |
| 70 | + 08740E47230E7DFA00B5D28D /* MoreFunctionsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MoreFunctionsView.m; sourceTree = "<group>"; }; | |
| 71 | + 08740E48230E7DFA00B5D28D /* AudioCfgView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AudioCfgView.m; sourceTree = "<group>"; }; | |
| 72 | + 08740E49230E7DFA00B5D28D /* FilterFunctionView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FilterFunctionView.h; sourceTree = "<group>"; }; | |
| 73 | + 08740E4A230E7DFA00B5D28D /* StreamerDetailViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StreamerDetailViewController.h; sourceTree = "<group>"; }; | |
| 74 | + 08740E4B230E7DFA00B5D28D /* CNLiveStreamerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CNLiveStreamerController.h; sourceTree = "<group>"; }; | |
| 75 | + 08740E4C230E7DFA00B5D28D /* SliderView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SliderView.h; sourceTree = "<group>"; }; | |
| 76 | + 08740E4D230E7DFA00B5D28D /* BgmPlayerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BgmPlayerView.m; sourceTree = "<group>"; }; | |
| 77 | + 08740E4E230E7DFA00B5D28D /* FloatingViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FloatingViewController.h; sourceTree = "<group>"; }; | |
| 78 | + 08740E4F230E7DFA00B5D28D /* MoreFunctionsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MoreFunctionsView.h; sourceTree = "<group>"; }; | |
| 79 | + 08740E50230E7DFA00B5D28D /* AudioStreamingViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioStreamingViewController.h; sourceTree = "<group>"; }; | |
| 80 | + 08740E5A230E83B100B5D28D /* LoadingView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoadingView.h; sourceTree = "<group>"; }; | |
| 81 | + 08740E5B230E83B100B5D28D /* LoadingView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LoadingView.m; sourceTree = "<group>"; }; | |
| 82 | + 08740E5D230E8A0700B5D28D /* house.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = house.gif; sourceTree = "<group>"; }; | |
| 83 | + 08740E60230E8C6500B5D28D /* CNLivePlayerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CNLivePlayerController.m; sourceTree = "<group>"; }; | |
| 84 | + 08740E61230E8C6500B5D28D /* CNLivePlayerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CNLivePlayerController.h; sourceTree = "<group>"; }; | |
| 56 | 85 | 17E088CE7F3FDB52D35B374B /* CNLivePlayer.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = CNLivePlayer.podspec; path = ../CNLivePlayer.podspec; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; |
| 57 | 86 | 26B97BD3DF7A4A551798F5CA /* Pods-CNLivePlayer_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CNLivePlayer_Tests.release.xcconfig"; path = "Target Support Files/Pods-CNLivePlayer_Tests/Pods-CNLivePlayer_Tests.release.xcconfig"; sourceTree = "<group>"; }; |
| 58 | 87 | 32AFD179FF73966F488CAFA0 /* Pods-CNLivePlayer_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CNLivePlayer_Example.debug.xcconfig"; path = "Target Support Files/Pods-CNLivePlayer_Example/Pods-CNLivePlayer_Example.debug.xcconfig"; sourceTree = "<group>"; }; |
| ... | ... | @@ -127,6 +156,43 @@ |
| 127 | 156 | path = Pods; |
| 128 | 157 | sourceTree = "<group>"; |
| 129 | 158 | }; |
| 159 | + 08740E3E230E7DFA00B5D28D /* Streamer */ = { | |
| 160 | + isa = PBXGroup; | |
| 161 | + children = ( | |
| 162 | + 08740E5D230E8A0700B5D28D /* house.gif */, | |
| 163 | + 08740E4B230E7DFA00B5D28D /* CNLiveStreamerController.h */, | |
| 164 | + 08740E3F230E7DFA00B5D28D /* CNLiveStreamerController.m */, | |
| 165 | + 08740E4A230E7DFA00B5D28D /* StreamerDetailViewController.h */, | |
| 166 | + 08740E40230E7DFA00B5D28D /* StreamerDetailViewController.m */, | |
| 167 | + 08740E5A230E83B100B5D28D /* LoadingView.h */, | |
| 168 | + 08740E5B230E83B100B5D28D /* LoadingView.m */, | |
| 169 | + 08740E50230E7DFA00B5D28D /* AudioStreamingViewController.h */, | |
| 170 | + 08740E46230E7DFA00B5D28D /* AudioStreamingViewController.m */, | |
| 171 | + 08740E4E230E7DFA00B5D28D /* FloatingViewController.h */, | |
| 172 | + 08740E45230E7DFA00B5D28D /* FloatingViewController.m */, | |
| 173 | + 08740E49230E7DFA00B5D28D /* FilterFunctionView.h */, | |
| 174 | + 08740E41230E7DFA00B5D28D /* FilterFunctionView.m */, | |
| 175 | + 08740E42230E7DFA00B5D28D /* AudioCfgView.h */, | |
| 176 | + 08740E48230E7DFA00B5D28D /* AudioCfgView.m */, | |
| 177 | + 08740E43230E7DFA00B5D28D /* BgmPlayerView.h */, | |
| 178 | + 08740E4D230E7DFA00B5D28D /* BgmPlayerView.m */, | |
| 179 | + 08740E4C230E7DFA00B5D28D /* SliderView.h */, | |
| 180 | + 08740E44230E7DFA00B5D28D /* SliderView.m */, | |
| 181 | + 08740E4F230E7DFA00B5D28D /* MoreFunctionsView.h */, | |
| 182 | + 08740E47230E7DFA00B5D28D /* MoreFunctionsView.m */, | |
| 183 | + ); | |
| 184 | + path = Streamer; | |
| 185 | + sourceTree = "<group>"; | |
| 186 | + }; | |
| 187 | + 08740E5F230E8C6500B5D28D /* Player */ = { | |
| 188 | + isa = PBXGroup; | |
| 189 | + children = ( | |
| 190 | + 08740E60230E8C6500B5D28D /* CNLivePlayerController.m */, | |
| 191 | + 08740E61230E8C6500B5D28D /* CNLivePlayerController.h */, | |
| 192 | + ); | |
| 193 | + path = Player; | |
| 194 | + sourceTree = "<group>"; | |
| 195 | + }; | |
| 130 | 196 | 6003F581195388D10070C39A = { |
| 131 | 197 | isa = PBXGroup; |
| 132 | 198 | children = ( |
| ... | ... | @@ -171,10 +237,8 @@ |
| 171 | 237 | children = ( |
| 172 | 238 | 6003F59C195388D20070C39A /* CNLiveAppDelegate.h */, |
| 173 | 239 | 6003F59D195388D20070C39A /* CNLiveAppDelegate.m */, |
| 174 | - 0807DF0C230799E000F409AC /* CNLivePlayerController.h */, | |
| 175 | - 0807DF0D230799E000F409AC /* CNLivePlayerController.m */, | |
| 176 | - 085FA986230D34890072B936 /* CNLiveStreamerController.h */, | |
| 177 | - 085FA987230D34890072B936 /* CNLiveStreamerController.m */, | |
| 240 | + 08740E5F230E8C6500B5D28D /* Player */, | |
| 241 | + 08740E3E230E7DFA00B5D28D /* Streamer */, | |
| 178 | 242 | 873B8AEA1B1F5CCA007FD442 /* Main.storyboard */, |
| 179 | 243 | 6003F5A5195388D20070C39A /* CNLiveViewController.h */, |
| 180 | 244 | 6003F5A6195388D20070C39A /* CNLiveViewController.m */, |
| ... | ... | @@ -311,6 +375,7 @@ |
| 311 | 375 | buildActionMask = 2147483647; |
| 312 | 376 | files = ( |
| 313 | 377 | 873B8AEB1B1F5CCA007FD442 /* Main.storyboard in Resources */, |
| 378 | + 08740E5E230E8A0700B5D28D /* house.gif in Resources */, | |
| 314 | 379 | 71719F9F1E33DC2100824A3D /* LaunchScreen.storyboard in Resources */, |
| 315 | 380 | 6003F5A9195388D20070C39A /* Images.xcassets in Resources */, |
| 316 | 381 | 6003F598195388D20070C39A /* InfoPlist.strings in Resources */, |
| ... | ... | @@ -381,6 +446,7 @@ |
| 381 | 446 | "${BUILT_PRODUCTS_DIR}/CocoaLumberjack/CocoaLumberjack.framework", |
| 382 | 447 | "${BUILT_PRODUCTS_DIR}/FMDB/FMDB.framework", |
| 383 | 448 | "${BUILT_PRODUCTS_DIR}/GPUImage/GPUImage.framework", |
| 449 | + "${BUILT_PRODUCTS_DIR}/YYImage/YYImage.framework", | |
| 384 | 450 | "${BUILT_PRODUCTS_DIR}/libksygpulive/libksygpulive.framework", |
| 385 | 451 | ); |
| 386 | 452 | name = "[CP] Embed Pods Frameworks"; |
| ... | ... | @@ -392,6 +458,7 @@ |
| 392 | 458 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CocoaLumberjack.framework", |
| 393 | 459 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FMDB.framework", |
| 394 | 460 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GPUImage.framework", |
| 461 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YYImage.framework", | |
| 395 | 462 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libksygpulive.framework", |
| 396 | 463 | ); |
| 397 | 464 | runOnlyForDeploymentPostprocessing = 0; |
| ... | ... | @@ -428,11 +495,20 @@ |
| 428 | 495 | isa = PBXSourcesBuildPhase; |
| 429 | 496 | buildActionMask = 2147483647; |
| 430 | 497 | files = ( |
| 498 | + 08740E58230E7DFB00B5D28D /* AudioCfgView.m in Sources */, | |
| 499 | + 08740E5C230E83B100B5D28D /* LoadingView.m in Sources */, | |
| 500 | + 08740E55230E7DFB00B5D28D /* FloatingViewController.m in Sources */, | |
| 431 | 501 | 6003F59E195388D20070C39A /* CNLiveAppDelegate.m in Sources */, |
| 432 | - 0807DF0E230799E000F409AC /* CNLivePlayerController.m in Sources */, | |
| 502 | + 08740E52230E7DFB00B5D28D /* StreamerDetailViewController.m in Sources */, | |
| 433 | 503 | 6003F5A7195388D20070C39A /* CNLiveViewController.m in Sources */, |
| 504 | + 08740E56230E7DFB00B5D28D /* AudioStreamingViewController.m in Sources */, | |
| 505 | + 08740E62230E8C6500B5D28D /* CNLivePlayerController.m in Sources */, | |
| 506 | + 08740E54230E7DFB00B5D28D /* SliderView.m in Sources */, | |
| 434 | 507 | 6003F59A195388D20070C39A /* main.m in Sources */, |
| 435 | - 085FA988230D34890072B936 /* CNLiveStreamerController.m in Sources */, | |
| 508 | + 08740E59230E7DFB00B5D28D /* BgmPlayerView.m in Sources */, | |
| 509 | + 08740E57230E7DFB00B5D28D /* MoreFunctionsView.m in Sources */, | |
| 510 | + 08740E53230E7DFB00B5D28D /* FilterFunctionView.m in Sources */, | |
| 511 | + 08740E51230E7DFB00B5D28D /* CNLiveStreamerController.m in Sources */, | |
| 436 | 512 | ); |
| 437 | 513 | runOnlyForDeploymentPostprocessing = 0; |
| 438 | 514 | }; | ... | ... |
Example/CNLivePlayer/CNLiveStreamerController.m deleted
100644 → 0
| 1 | -// | |
| 2 | -// CNLiveStreamerController.m | |
| 3 | -// CNLivePlayer_Example | |
| 4 | -// | |
| 5 | -// Created by CNLive-zxw on 2019/8/21. | |
| 6 | -// Copyright © 2019 153993236@qq.com. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "CNLiveStreamerController.h" | |
| 10 | - | |
| 11 | -@interface CNLiveStreamerController () | |
| 12 | - | |
| 13 | -@end | |
| 14 | - | |
| 15 | -@implementation CNLiveStreamerController | |
| 16 | - | |
| 17 | -- (void)viewDidLoad { | |
| 18 | - [super viewDidLoad]; | |
| 19 | - // Do any additional setup after loading the view. | |
| 20 | - self.view.backgroundColor = [UIColor whiteColor]; | |
| 21 | - UIButton *btn2 = [UIButton buttonWithType:UIButtonTypeCustom]; | |
| 22 | - btn2.frame = CGRectMake(0, 0, 100, 50); | |
| 23 | - btn2.center = CGPointMake(self.view.center.x, self.view.center.y+50); | |
| 24 | - btn2.backgroundColor = [UIColor redColor]; | |
| 25 | - [btn2 setTitle:@"返回" forState:UIControlStateNormal]; | |
| 26 | - [btn2 setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; | |
| 27 | - [btn2 addTarget:self action:@selector(btnDidClicked2) forControlEvents:UIControlEventTouchUpInside]; | |
| 28 | - [self.view addSubview:btn2]; | |
| 29 | -} | |
| 30 | - | |
| 31 | - | |
| 32 | -- (void)btnDidClicked2{ | |
| 33 | - [self dismissViewControllerAnimated:YES completion:nil]; | |
| 34 | - | |
| 35 | -} | |
| 36 | - | |
| 37 | -/* | |
| 38 | -#pragma mark - Navigation | |
| 39 | - | |
| 40 | -// In a storyboard-based application, you will often want to do a little preparation before navigation | |
| 41 | -- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { | |
| 42 | - // Get the new view controller using [segue destinationViewController]. | |
| 43 | - // Pass the selected object to the new view controller. | |
| 44 | -} | |
| 45 | -*/ | |
| 46 | - | |
| 47 | -@end |
Example/CNLivePlayer/Images.xcassets/Contents.json
0 → 100644
Example/CNLivePlayer/Images.xcassets/Streamer/Contents.json
0 → 100644
Example/CNLivePlayer/Images.xcassets/Streamer/back.imageset/Contents.json
0 → 100644
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "idiom" : "universal", | |
| 5 | + "filename" : "back.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 | ... | ... |
Example/CNLivePlayer/Images.xcassets/Streamer/back.imageset/back.png
0 → 100644
1.16 KB
Example/CNLivePlayer/Images.xcassets/Streamer/big_pause_button.imageset/Contents.json
0 → 100644
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "idiom" : "universal", | |
| 5 | + "filename" : "big_pause_button.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 | ... | ... |
Example/CNLivePlayer/Images.xcassets/Streamer/big_pause_button.imageset/big_pause_button.png
0 → 100644
3.7 KB
Example/CNLivePlayer/Images.xcassets/Streamer/big_play_button.imageset/Contents.json
0 → 100644
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "idiom" : "universal", | |
| 5 | + "filename" : "big_play_button.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 | ... | ... |
Example/CNLivePlayer/Images.xcassets/Streamer/big_play_button.imageset/big_play_button.png
0 → 100644
3.68 KB
Example/CNLivePlayer/Images.xcassets/Streamer/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 | ... | ... |
Example/CNLivePlayer/Images.xcassets/Streamer/btn_dot.imageset/btn_dot.png
0 → 100644
627 Bytes
Example/CNLivePlayer/Images.xcassets/Streamer/cache setting.imageset/Contents.json
0 → 100644
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "idiom" : "universal", | |
| 5 | + "filename" : "cache setting.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 | ... | ... |
Example/CNLivePlayer/Images.xcassets/Streamer/cache setting.imageset/cache setting.png
0 → 100644
1.26 KB
Example/CNLivePlayer/Images.xcassets/Streamer/camera.imageset/Contents.json
0 → 100644
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "idiom" : "universal", | |
| 5 | + "filename" : "camera.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 | ... | ... |
Example/CNLivePlayer/Images.xcassets/Streamer/camera.imageset/camera.png
0 → 100644
1.4 KB
Example/CNLivePlayer/Images.xcassets/Streamer/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 | ... | ... |
Example/CNLivePlayer/Images.xcassets/Streamer/cancel.imageset/cancel.png
0 → 100644
1.14 KB
Example/CNLivePlayer/Images.xcassets/Streamer/fanhui.imageset/Contents.json
0 → 100644
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "idiom" : "universal", | |
| 5 | + "filename" : "fanhui.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 | ... | ... |
Example/CNLivePlayer/Images.xcassets/Streamer/fanhui.imageset/fanhui.png
0 → 100644
983 Bytes
Example/CNLivePlayer/Images.xcassets/Streamer/filter.imageset/Contents.json
0 → 100644
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "idiom" : "universal", | |
| 5 | + "filename" : "filter.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 | ... | ... |
Example/CNLivePlayer/Images.xcassets/Streamer/filter.imageset/filter.png
0 → 100644
1.18 KB
Example/CNLivePlayer/Images.xcassets/Streamer/flash close.imageset/Contents.json
0 → 100644
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "idiom" : "universal", | |
| 5 | + "filename" : "flash close.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 | ... | ... |
Example/CNLivePlayer/Images.xcassets/Streamer/flash close.imageset/flash close.png
0 → 100644
1.13 KB
Example/CNLivePlayer/Images.xcassets/Streamer/flash open.imageset/Contents.json
0 → 100644
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "idiom" : "universal", | |
| 5 | + "filename" : "flash open.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 | ... | ... |
Example/CNLivePlayer/Images.xcassets/Streamer/flash open.imageset/flash open.png
0 → 100644
1.21 KB
Example/CNLivePlayer/Images.xcassets/Streamer/loop_all_icon.imageset/Contents.json
0 → 100644
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "idiom" : "universal", | |
| 5 | + "filename" : "loop_all_icon.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 | ... | ... |
Example/CNLivePlayer/Images.xcassets/Streamer/loop_all_icon.imageset/loop_all_icon.png
0 → 100644
840 Bytes
Example/CNLivePlayer/Images.xcassets/Streamer/loop_single_icon.imageset/Contents.json
0 → 100644
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "idiom" : "universal", | |
| 5 | + "filename" : "loop_single_icon.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 | ... | ... |
Example/CNLivePlayer/Images.xcassets/Streamer/loop_single_icon.imageset/loop_single_icon.png
0 → 100644
948 Bytes
Example/CNLivePlayer/Images.xcassets/Streamer/menu.imageset/Contents.json
0 → 100644
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "idiom" : "universal", | |
| 5 | + "filename" : "menu.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 | ... | ... |
Example/CNLivePlayer/Images.xcassets/Streamer/menu.imageset/menu.png
0 → 100644
296 Bytes
Example/CNLivePlayer/Images.xcassets/Streamer/music_slider_circle.imageset/Contents.json
0 → 100644
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "idiom" : "universal", | |
| 5 | + "filename" : "music_slider_circle.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 | ... | ... |
Example/CNLivePlayer/Images.xcassets/Streamer/music_slider_circle.imageset/music_slider_circle.png
0 → 100644
1.07 KB
Example/CNLivePlayer/Images.xcassets/Streamer/next_song.imageset/Contents.json
0 → 100644
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "idiom" : "universal", | |
| 5 | + "filename" : "next_song.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 | ... | ... |
Example/CNLivePlayer/Images.xcassets/Streamer/next_song.imageset/next_song.png
0 → 100644
814 Bytes
Example/CNLivePlayer/Images.xcassets/Streamer/pause.imageset/Contents.json
0 → 100644
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "idiom" : "universal", | |
| 5 | + "filename" : "pause.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 | ... | ... |
Example/CNLivePlayer/Images.xcassets/Streamer/pause.imageset/pause.png
0 → 100644
3.15 KB
Example/CNLivePlayer/Images.xcassets/Streamer/play.imageset/Contents.json
0 → 100644
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "idiom" : "universal", | |
| 5 | + "filename" : "play.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 | ... | ... |
Example/CNLivePlayer/Images.xcassets/Streamer/play.imageset/play.png
0 → 100644
6.41 KB
Example/CNLivePlayer/Images.xcassets/Streamer/prev_song.imageset/Contents.json
0 → 100644
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "idiom" : "universal", | |
| 5 | + "filename" : "prev_song.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 | ... | ... |
Example/CNLivePlayer/Images.xcassets/Streamer/prev_song.imageset/prev_song.png
0 → 100644
845 Bytes
Example/CNLivePlayer/Images.xcassets/Streamer/shuffle_icon.imageset/Contents.json
0 → 100644
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "idiom" : "universal", | |
| 5 | + "filename" : "shuffle_icon.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 | ... | ... |
Example/CNLivePlayer/Images.xcassets/Streamer/shuffle_icon.imageset/shuffle_icon.png
0 → 100644
802 Bytes
Example/CNLivePlayer/Images.xcassets/Streamer/voice.imageset/Contents.json
0 → 100644
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "idiom" : "universal", | |
| 5 | + "filename" : "voice.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 | ... | ... |
Example/CNLivePlayer/Images.xcassets/Streamer/voice.imageset/voice.png
0 → 100644
1.27 KB
Example/CNLivePlayer/Images.xcassets/Streamer/互动电视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 | ... | ... |
Example/CNLivePlayer/Images.xcassets/Streamer/互动电视180x180.imageset/互动电视180x180.png
0 → 100644
21.2 KB
Example/CNLivePlayer/Images.xcassets/Streamer/更多.imageset/Contents.json
0 → 100644
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "idiom" : "universal", | |
| 5 | + "filename" : "更多.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 | ... | ... |
Example/CNLivePlayer/Images.xcassets/Streamer/更多.imageset/更多.png
0 → 100644
1.38 KB
Example/CNLivePlayer/Images.xcassets/Streamer/背景.imageset/Contents.json
0 → 100644
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "idiom" : "universal", | |
| 5 | + "filename" : "背景.jpg", | |
| 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 | ... | ... |
Example/CNLivePlayer/Images.xcassets/Streamer/背景.imageset/背景.jpg
0 → 100644
17.1 KB
Example/CNLivePlayer/CNLivePlayerController.h renamed to Example/CNLivePlayer/Player/CNLivePlayerController.h
Example/CNLivePlayer/CNLivePlayerController.m renamed to Example/CNLivePlayer/Player/CNLivePlayerController.m
Example/CNLivePlayer/Streamer/AudioCfgView.h
0 → 100644
| 1 | +// | |
| 2 | +// AudioCfgView.h | |
| 3 | +// CNLivePlayerSDKDemo | |
| 4 | +// | |
| 5 | +// Created by iOS on 17/4/26. | |
| 6 | +// Copyright © 2017年 雷浩杰. All rights reserved. | |
| 7 | +// | |
| 8 | + | |
| 9 | +#import <UIKit/UIKit.h> | |
| 10 | + | |
| 11 | +typedef void(^AudioEffectBlock)(int type); //音效回调 | |
| 12 | +typedef void(^ReverbTypeBlock)(int type); //混响回调 | |
| 13 | +typedef void(^BPlayCapturedAudioBlock)(BOOL isOn); //是否开启耳返 | |
| 14 | +typedef void(^MicVolumeBlock)(float micVolume); //麦克风音量 | |
| 15 | +typedef void(^BPlayVolumeBlock)(float bPlayVolume); //耳返音量 | |
| 16 | + | |
| 17 | +@interface AudioCfgView : UIView | |
| 18 | + | |
| 19 | +@property (nonatomic, strong) UISwitch *bPlaySwitch; | |
| 20 | + | |
| 21 | +@property (nonatomic, copy) AudioEffectBlock audioEffectBlock; | |
| 22 | +@property (nonatomic, copy) ReverbTypeBlock reverbTypeBlock; | |
| 23 | +@property (nonatomic, copy) BPlayCapturedAudioBlock bPlayCapturedAudio; | |
| 24 | +@property (nonatomic, copy) MicVolumeBlock micVolumeBlock; | |
| 25 | +@property (nonatomic, copy) BPlayVolumeBlock bPlayVolumeBlock; | |
| 26 | + | |
| 27 | +@end | ... | ... |
Example/CNLivePlayer/Streamer/AudioCfgView.m
0 → 100644
| 1 | +// | |
| 2 | +// AudioCfgView.m | |
| 3 | +// CNLivePlayerSDKDemo | |
| 4 | +// | |
| 5 | +// Created by iOS on 17/4/26. | |
| 6 | +// Copyright © 2017年 雷浩杰. All rights reserved. | |
| 7 | +// | |
| 8 | + | |
| 9 | +#import "AudioCfgView.h" | |
| 10 | + | |
| 11 | +@interface AudioCfgView () | |
| 12 | + | |
| 13 | +@property (nonatomic, strong) UISegmentedControl *audioEffectType; | |
| 14 | +@property (nonatomic, strong) UISegmentedControl *reverbType; | |
| 15 | +@property (nonatomic, strong) UISlider *micVolumeSlider; | |
| 16 | +@property (nonatomic, strong) UISlider *bPlayVolumeSlider; | |
| 17 | + | |
| 18 | +@end | |
| 19 | + | |
| 20 | +@implementation AudioCfgView | |
| 21 | + | |
| 22 | +- (instancetype)initWithFrame:(CGRect)frame | |
| 23 | +{ | |
| 24 | + self = [super initWithFrame:frame]; | |
| 25 | + if (self) { | |
| 26 | + self.backgroundColor = [UIColor colorWithWhite:0 alpha:0.1]; | |
| 27 | + [self addSubview:self.audioEffectType]; | |
| 28 | + [self addSubview:self.reverbType]; | |
| 29 | + [self addSubview:self.bPlaySwitch]; | |
| 30 | + [self addSubview:self.micVolumeSlider]; | |
| 31 | + [self addSubview:self.bPlayVolumeSlider]; | |
| 32 | + } | |
| 33 | + return self; | |
| 34 | +} | |
| 35 | + | |
| 36 | +#pragma mark - | |
| 37 | +#pragma mark - action | |
| 38 | +- (void)audioEffect:(UISegmentedControl *)sender { | |
| 39 | + self.audioEffectBlock ? self.audioEffectBlock((int)sender.selectedSegmentIndex) : nil; | |
| 40 | +} | |
| 41 | + | |
| 42 | +- (void)reverbType:(UISegmentedControl *)sender { | |
| 43 | + self.reverbTypeBlock ? self.reverbTypeBlock((int)sender.selectedSegmentIndex) : nil; | |
| 44 | +} | |
| 45 | + | |
| 46 | +-(void)switchAction:(id)sender { | |
| 47 | + UISwitch *swi = (UISwitch *)sender; | |
| 48 | + self.bPlayCapturedAudio ? self.bPlayCapturedAudio(swi.on) : nil; | |
| 49 | +} | |
| 50 | + | |
| 51 | +- (void)micVolumeChanged:(UISlider *)slider { | |
| 52 | + self.micVolumeBlock ? self.micVolumeBlock(slider.value) : nil; | |
| 53 | +} | |
| 54 | + | |
| 55 | +- (void)bPlayVolumeChanged:(UISlider *)slider { | |
| 56 | + self.bPlayVolumeBlock ? self.bPlayVolumeBlock(slider.value) : nil; | |
| 57 | +} | |
| 58 | + | |
| 59 | +#pragma mark - | |
| 60 | +#pragma mark - getter | |
| 61 | +- (UISegmentedControl *)audioEffectType | |
| 62 | +{ | |
| 63 | + if (!_audioEffectType) { | |
| 64 | + NSArray *items = @[ @"关闭", | |
| 65 | + @"大叔", | |
| 66 | + @"萝莉", | |
| 67 | + @"庄严", | |
| 68 | + @"机器人"]; | |
| 69 | + | |
| 70 | + _audioEffectType = [[UISegmentedControl alloc] initWithItems:items]; | |
| 71 | + _audioEffectType.frame = CGRectMake(60, 50, self.bounds.size.width-70, 30); | |
| 72 | + _audioEffectType.tintColor= [UIColor blackColor]; | |
| 73 | + _audioEffectType.selectedSegmentIndex = 0; | |
| 74 | + _audioEffectType.layer.cornerRadius = 5; | |
| 75 | + [_audioEffectType addTarget:self action:@selector(audioEffect:) forControlEvents:UIControlEventValueChanged]; | |
| 76 | + | |
| 77 | + UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, 55, 40, 20)]; | |
| 78 | + label.text = @"变声"; | |
| 79 | + [self addSubview:label]; | |
| 80 | + } | |
| 81 | + return _audioEffectType; | |
| 82 | +} | |
| 83 | + | |
| 84 | +- (UISegmentedControl *)reverbType | |
| 85 | +{ | |
| 86 | + if (!_reverbType) { | |
| 87 | + NSArray *items = @[ @"关闭", | |
| 88 | + @"录音棚", | |
| 89 | + @"演唱会", | |
| 90 | + @"KTV", | |
| 91 | + @"小舞台"]; | |
| 92 | + | |
| 93 | + _reverbType = [[UISegmentedControl alloc] initWithItems:items]; | |
| 94 | + _reverbType.frame = CGRectMake(60, 90, self.bounds.size.width-70, 30); | |
| 95 | + _reverbType.tintColor= [UIColor blackColor]; | |
| 96 | + _reverbType.selectedSegmentIndex = 0; | |
| 97 | + _reverbType.layer.cornerRadius = 5; | |
| 98 | + [_reverbType addTarget:self action:@selector(reverbType:) forControlEvents:UIControlEventValueChanged]; | |
| 99 | + | |
| 100 | + UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, 95, 40, 20)]; | |
| 101 | + label.text = @"混响"; | |
| 102 | + [self addSubview:label]; | |
| 103 | + } | |
| 104 | + return _reverbType; | |
| 105 | +} | |
| 106 | + | |
| 107 | +- (UISwitch *)bPlaySwitch | |
| 108 | +{ | |
| 109 | + if (!_bPlaySwitch) { | |
| 110 | + _bPlaySwitch = [[UISwitch alloc] initWithFrame:CGRectMake(60, 10, 100, 30)]; | |
| 111 | + [_bPlaySwitch addTarget:self action:@selector(switchAction:) forControlEvents:UIControlEventValueChanged]; | |
| 112 | + UILabel *modeLab = [[UILabel alloc] initWithFrame:CGRectMake(10, 15, 40, 20)]; | |
| 113 | + modeLab.textColor = [UIColor blackColor]; | |
| 114 | + modeLab.text = @"耳返"; | |
| 115 | + [self addSubview:modeLab]; | |
| 116 | + } | |
| 117 | + return _bPlaySwitch; | |
| 118 | +} | |
| 119 | + | |
| 120 | +- (UISlider *)micVolumeSlider | |
| 121 | +{ | |
| 122 | + if (!_micVolumeSlider) { | |
| 123 | + _micVolumeSlider = [[UISlider alloc] initWithFrame:CGRectMake(100, 135, self.bounds.size.width-110, 24)]; | |
| 124 | + [_micVolumeSlider setMinimumTrackTintColor:[UIColor redColor]]; | |
| 125 | + [_micVolumeSlider setMaximumTrackTintColor:[UIColor whiteColor]]; | |
| 126 | + _micVolumeSlider.value = 1.0; | |
| 127 | + [_micVolumeSlider addTarget:self action:@selector(micVolumeChanged:) forControlEvents:UIControlEventValueChanged]; | |
| 128 | + [_micVolumeSlider setThumbImage:[UIImage imageNamed:@"btn_dot"] forState:UIControlStateNormal]; | |
| 129 | + | |
| 130 | + | |
| 131 | + UILabel *micLab = [[UILabel alloc] initWithFrame:CGRectMake(10, 135, 90, 20)]; | |
| 132 | + micLab.textColor = [UIColor blackColor]; | |
| 133 | + micLab.text = @"麦克风音量"; | |
| 134 | + [self addSubview:micLab]; | |
| 135 | + } | |
| 136 | + return _micVolumeSlider; | |
| 137 | +} | |
| 138 | + | |
| 139 | +- (UISlider *)bPlayVolumeSlider | |
| 140 | +{ | |
| 141 | + if (!_bPlayVolumeSlider) { | |
| 142 | + _bPlayVolumeSlider = [[UISlider alloc] initWithFrame:CGRectMake(100, 170, self.bounds.size.width-110, 24)]; | |
| 143 | + _bPlayVolumeSlider.value = 1.0; | |
| 144 | + [_bPlayVolumeSlider setMinimumTrackTintColor:[UIColor redColor]]; | |
| 145 | + [_bPlayVolumeSlider setMaximumTrackTintColor:[UIColor whiteColor]]; | |
| 146 | + [_bPlayVolumeSlider addTarget:self action:@selector(bPlayVolumeChanged:) forControlEvents:UIControlEventValueChanged]; | |
| 147 | + [_bPlayVolumeSlider setThumbImage:[UIImage imageNamed:@"btn_dot"] forState:UIControlStateNormal]; | |
| 148 | + | |
| 149 | + UILabel *micLab = [[UILabel alloc] initWithFrame:CGRectMake(10, 170, 80, 20)]; | |
| 150 | + micLab.textColor = [UIColor blackColor]; | |
| 151 | + micLab.text = @"耳返音量"; | |
| 152 | + [self addSubview:micLab]; | |
| 153 | + } | |
| 154 | + return _bPlayVolumeSlider; | |
| 155 | +} | |
| 156 | + | |
| 157 | +/* | |
| 158 | +// Only override drawRect: if you perform custom drawing. | |
| 159 | +// An empty implementation adversely affects performance during animation. | |
| 160 | +- (void)drawRect:(CGRect)rect { | |
| 161 | + // Drawing code | |
| 162 | +} | |
| 163 | +*/ | |
| 164 | + | |
| 165 | +@end | ... | ... |
Example/CNLivePlayer/Streamer/AudioStreamingViewController.h
0 → 100644
| 1 | +// | |
| 2 | +// AudioStreamingViewController.h | |
| 3 | +// CNLivePlayerSDKDemo | |
| 4 | +// | |
| 5 | +// Created by iOS on 17/4/26. | |
| 6 | +// Copyright © 2017年 雷浩杰. All rights reserved. | |
| 7 | +// | |
| 8 | + | |
| 9 | +#import <UIKit/UIKit.h> | |
| 10 | + | |
| 11 | +@interface AudioStreamingViewController : UIViewController | |
| 12 | + | |
| 13 | +@property (nonatomic, assign) BOOL isAuthLive; | |
| 14 | + | |
| 15 | +@property (nonatomic, strong) NSURL *url; | |
| 16 | + | |
| 17 | +@end | ... | ... |
Example/CNLivePlayer/Streamer/AudioStreamingViewController.m
0 → 100644
| 1 | +// | |
| 2 | +// AudioStreamingViewController.m | |
| 3 | +// CNLivePlayerSDKDemo | |
| 4 | +// | |
| 5 | +// Created by iOS on 17/4/26. | |
| 6 | +// Copyright © 2017年 雷浩杰. All rights reserved. | |
| 7 | +// | |
| 8 | + | |
| 9 | +#import "AudioStreamingViewController.h" | |
| 10 | +#import "CNLiveStreamerManager.h" | |
| 11 | +#import "CNLiveStreamerKit.h" | |
| 12 | +#import "AudioCfgView.h" | |
| 13 | +#import "BgmPlayerView.h" | |
| 14 | +#import "CNLiveStreamerBase.h" | |
| 15 | +#import "CNLiveWatermark.h" | |
| 16 | +#import "CNLiveAudioCapture.h" | |
| 17 | +#import "CNLiveBgmPlayer.h" | |
| 18 | + | |
| 19 | +#define Width [UIScreen mainScreen].bounds.size.width | |
| 20 | +#define Height [UIScreen mainScreen].bounds.size.height | |
| 21 | + | |
| 22 | +@interface AudioStreamingViewController ()<BgmPlayerViewDelegate> | |
| 23 | +{ | |
| 24 | + UIButton *_startLiveBtn; | |
| 25 | + NSArray *_listArr; | |
| 26 | + NSInteger _currentIndex; | |
| 27 | + NSTimer *_currentTimer; | |
| 28 | + BOOL _playMode; //播放模式 | |
| 29 | +} | |
| 30 | + | |
| 31 | +@property (nonatomic,strong) CNLiveStreamerKit *kitCN; //直播推流 | |
| 32 | +@property (nonatomic,strong) UILabel *stateLab; | |
| 33 | +@property (nonatomic,strong) AudioCfgView *audioCfgView; //声音相关设置 | |
| 34 | +@property (nonatomic,strong) BgmPlayerView *bgmPlayerView; //背景音乐 | |
| 35 | + | |
| 36 | +@end | |
| 37 | + | |
| 38 | +@implementation AudioStreamingViewController | |
| 39 | + | |
| 40 | +- (void)viewDidLoad { | |
| 41 | + [super viewDidLoad]; | |
| 42 | + // Do any additional setup after loading the view. | |
| 43 | + self.view.backgroundColor = [UIColor whiteColor]; | |
| 44 | + [self.view addSubview:self.stateLab]; | |
| 45 | + [self.view addSubview:self.audioCfgView]; | |
| 46 | + [self.view addSubview:self.bgmPlayerView]; | |
| 47 | + | |
| 48 | + _currentTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(timeChange) userInfo:nil repeats:YES]; | |
| 49 | + | |
| 50 | + | |
| 51 | + if (_isAuthLive) { | |
| 52 | + | |
| 53 | + NSDate *date = [NSDate date]; | |
| 54 | + NSInteger time = [date timeIntervalSince1970]; | |
| 55 | + NSString *activityId = [NSString stringWithFormat:@"%ld", (long)time]; | |
| 56 | + | |
| 57 | + _kitCN = [[CNLiveStreamerKit alloc] initPureAudioStreamerWithDefaultConfig]; | |
| 58 | + _kitCN.activityId = activityId; | |
| 59 | + _kitCN.channelId = @"iostest"; | |
| 60 | + | |
| 61 | + [self setStreamerCfg]; | |
| 62 | + [self addObservers]; | |
| 63 | + | |
| 64 | + }else{ | |
| 65 | + | |
| 66 | + _kitCN = [[CNLiveStreamerKit alloc] initWithDefaultConfig:YES]; | |
| 67 | + | |
| 68 | + [self setStreamerCfg]; | |
| 69 | + [self addObservers]; | |
| 70 | + | |
| 71 | + } | |
| 72 | + | |
| 73 | + _startLiveBtn = [self addButton:@"开始直播" frame:CGRectMake(10, 40, 80, 40) action:@selector(startStreaming:)]; | |
| 74 | + [_startLiveBtn setTitle:@"开始直播" forState:UIControlStateNormal]; | |
| 75 | + [_startLiveBtn setTitle:@"停止直播" forState:UIControlStateSelected]; | |
| 76 | + | |
| 77 | + [self addButton:@"退出" frame:CGRectMake(100, 40, 80, 40) action:@selector(quit)]; | |
| 78 | + [self addButton:@"背景音乐" frame:CGRectMake(10, 100, 80, 40) action:@selector(bgmPlayerBtnAction:)]; | |
| 79 | + [self addButton:@"声音" frame:CGRectMake(100, 100, 80, 40) action:@selector(voiceBtnAction:)]; | |
| 80 | + | |
| 81 | + _listArr = @[@" See You Again ", | |
| 82 | + @"Idina Menzel - Let It Go", | |
| 83 | + @"Morrie - Lullaby", | |
| 84 | + @"Zedd,Alessia Cara - Stay"]; | |
| 85 | +} | |
| 86 | + | |
| 87 | +- (void)setStreamerCfg { | |
| 88 | + _kitCN.streamerBase.audiokBPS = 48; | |
| 89 | + | |
| 90 | + //声音相关设置 | |
| 91 | + __weak AudioStreamingViewController *weakself = self; | |
| 92 | + | |
| 93 | + _audioCfgView.audioEffectBlock = ^(int type) { //音效 | |
| 94 | + weakself.kitCN.audioCapture.audioEffectType = type; | |
| 95 | + }; | |
| 96 | + | |
| 97 | + _audioCfgView.reverbTypeBlock = ^(int type) { //混响 | |
| 98 | + weakself.kitCN.audioCapture.reverbType = type; | |
| 99 | + }; | |
| 100 | + | |
| 101 | + _audioCfgView.bPlayCapturedAudio = ^(BOOL isOn) { //耳返 | |
| 102 | + if ([CNLiveAudioCapture isHeadsetPluggedIn]) { | |
| 103 | + [weakself.kitCN.audioCapture setBPlayCapturedAudio:isOn]; | |
| 104 | + } else { | |
| 105 | + weakself.audioCfgView.bPlaySwitch.on = NO; | |
| 106 | + [weakself toast:@"未检测到耳机"]; | |
| 107 | + } | |
| 108 | + }; | |
| 109 | + | |
| 110 | + _audioCfgView.micVolumeBlock = ^(float micVolume) { //麦克风音量 | |
| 111 | + weakself.kitCN.audioCapture.micVolume = micVolume; | |
| 112 | + }; | |
| 113 | + | |
| 114 | + _audioCfgView.bPlayVolumeBlock = ^(float bPlayVolume) { //耳返音量 | |
| 115 | + weakself.kitCN.audioCapture.bPlayVolume = bPlayVolume; | |
| 116 | + }; | |
| 117 | + | |
| 118 | + _kitCN.bgmPlayer.cnBgmFinishBlock = ^{ | |
| 119 | + if (!_playMode) { | |
| 120 | + if (_currentIndex != 3) { | |
| 121 | + _currentIndex ++; | |
| 122 | + [_kitCN.bgmPlayer stopPlayBgm]; | |
| 123 | + [_kitCN.bgmPlayer startPlayBgm:[[NSBundle mainBundle] pathForResource:_listArr[_currentIndex] ofType:@"mp3"] isLoop:_playMode]; | |
| 124 | + _bgmPlayerView.songTitleLab.text = _listArr[_currentIndex]; | |
| 125 | + } | |
| 126 | + } | |
| 127 | + }; | |
| 128 | + | |
| 129 | +} | |
| 130 | + | |
| 131 | +- (UIButton *)addButton:(NSString*)title | |
| 132 | + frame:(CGRect)frame | |
| 133 | + action:(SEL)action { | |
| 134 | + UIButton * button; | |
| 135 | + button = [UIButton buttonWithType:UIButtonTypeCustom]; | |
| 136 | + button.frame = frame; | |
| 137 | + [button setTitle: title forState: UIControlStateNormal]; | |
| 138 | + [button addTarget:self action:action forControlEvents:UIControlEventTouchUpInside]; | |
| 139 | + button.titleLabel.font = [UIFont systemFontOfSize:15]; | |
| 140 | + [button setTitleColor:[UIColor colorWithRed:23/255.0 green:110/255.0 blue:254/255.0 alpha:1] forState:UIControlStateNormal]; | |
| 141 | + button.layer.cornerRadius = 10; | |
| 142 | + button.layer.masksToBounds = YES; | |
| 143 | + button.layer.borderColor = [UIColor blackColor].CGColor; | |
| 144 | + button.layer.borderWidth = 1; | |
| 145 | + [self.view addSubview:button]; | |
| 146 | + return button; | |
| 147 | + | |
| 148 | +} | |
| 149 | + | |
| 150 | +#pragma mark - | |
| 151 | +#pragma mark - action | |
| 152 | +- (void)startStreaming:(UIButton *)button { | |
| 153 | + button.selected = !button.selected; | |
| 154 | + | |
| 155 | + if (button.selected) { | |
| 156 | + | |
| 157 | + if (_isAuthLive) { | |
| 158 | + | |
| 159 | + [_kitCN startStream:^{ | |
| 160 | + NSLog(@"开启推流成功 ------- success"); | |
| 161 | + } failure:^(NSDictionary *errorDic) { | |
| 162 | + [self toast:errorDic[@"errorMessage"]]; | |
| 163 | + _startLiveBtn.selected = NO; | |
| 164 | + }]; | |
| 165 | + | |
| 166 | + }else{ | |
| 167 | + [_kitCN startStream:self.url]; | |
| 168 | + } | |
| 169 | + }else{ | |
| 170 | + _stateLab.text = nil; | |
| 171 | + [_kitCN stopStream]; | |
| 172 | + } | |
| 173 | +} | |
| 174 | + | |
| 175 | +- (void)quit { | |
| 176 | + if (_kitCN.streamState == CNLiveStreamStateConnected) { | |
| 177 | + [_kitCN stopStream]; | |
| 178 | + } | |
| 179 | + | |
| 180 | + if (_kitCN.bgmPlayer.isRunning) { | |
| 181 | + [_kitCN.bgmPlayer stopPlayBgm]; | |
| 182 | + } | |
| 183 | + | |
| 184 | + if (_currentTimer) { | |
| 185 | + [_currentTimer invalidate]; | |
| 186 | + _currentTimer = nil; | |
| 187 | + } | |
| 188 | + | |
| 189 | + [_kitCN quitStreaming]; | |
| 190 | + self.kitCN = nil; | |
| 191 | + [[NSNotificationCenter defaultCenter] removeObserver:self]; | |
| 192 | + | |
| 193 | + [self dismissViewControllerAnimated:YES completion:NULL]; | |
| 194 | +} | |
| 195 | + | |
| 196 | +- (void)bgmPlayerBtnAction:(UIButton *)button { | |
| 197 | + _audioCfgView.hidden = YES; | |
| 198 | + _bgmPlayerView.hidden = button.selected; | |
| 199 | + button.selected = !button.selected; | |
| 200 | +} | |
| 201 | + | |
| 202 | +- (void)voiceBtnAction:(UIButton *)button { | |
| 203 | + _bgmPlayerView.hidden = YES; | |
| 204 | + _audioCfgView.hidden = button.selected; | |
| 205 | + button.selected = !button.selected; | |
| 206 | +} | |
| 207 | + | |
| 208 | +- (void)timeChange | |
| 209 | +{ | |
| 210 | + _bgmPlayerView.proSlider.value = _kitCN.bgmPlayer.bgmPlayTime/_kitCN.bgmPlayer.bgmDuration; | |
| 211 | + _bgmPlayerView.currentTimeLab.text = [self getMMSSFromSS:[NSString stringWithFormat:@"%f",_kitCN.bgmPlayer.bgmPlayTime]]; | |
| 212 | + _bgmPlayerView.duraTimeLab.text = [self getMMSSFromSS:[NSString stringWithFormat:@"%f",_kitCN.bgmPlayer.bgmDuration]]; | |
| 213 | +} | |
| 214 | + | |
| 215 | +- (NSString *)getMMSSFromSS:(NSString *)totalTime { | |
| 216 | + NSInteger seconds = [totalTime integerValue]; | |
| 217 | + NSString *str_minute = [NSString stringWithFormat:@"%02ld",(seconds%3600)/60]; | |
| 218 | + NSString *str_second = [NSString stringWithFormat:@"%02ld",seconds%60]; | |
| 219 | + NSString *format_time = [NSString stringWithFormat:@"%@:%@",str_minute,str_second]; | |
| 220 | + return format_time; | |
| 221 | +} | |
| 222 | + | |
| 223 | +#pragma mark - | |
| 224 | +#pragma mark - BgmPlayerViewDelegate | |
| 225 | +- (void)valueType:(BOOL)isVolume value:(float)value { | |
| 226 | + if (isVolume) { | |
| 227 | + _kitCN.bgmPlayer.bgmVolume = value; | |
| 228 | + } else { | |
| 229 | + _kitCN.bgmPlayer.bgmPitch = value; | |
| 230 | + } | |
| 231 | +} | |
| 232 | + | |
| 233 | +- (void)bgmPlayerPlay:(UIButton *)button { | |
| 234 | + if (_kitCN.bgmPlayer.isRunning) { | |
| 235 | + [_kitCN.bgmPlayer stopPlayBgm]; | |
| 236 | + } else { | |
| 237 | + NSString *path = [[NSBundle mainBundle] pathForResource:_listArr[_currentIndex] ofType:@"mp3"]; | |
| 238 | + _bgmPlayerView.songTitleLab.text = _listArr[_currentIndex]; | |
| 239 | + [_kitCN.bgmPlayer startPlayBgm:path isLoop:_playMode]; | |
| 240 | + } | |
| 241 | +} | |
| 242 | + | |
| 243 | +- (void)bgmPlayerMode:(UIButton *)button { | |
| 244 | + _kitCN.bgmPlayer.bLoop = button.selected; | |
| 245 | + _playMode = _kitCN.bgmPlayer.bLoop; | |
| 246 | +} | |
| 247 | + | |
| 248 | +- (void)bgmPlayerPauseOrResume:(UIButton *)button { | |
| 249 | + if (button.selected) { | |
| 250 | + [_kitCN.bgmPlayer pauseBgm]; | |
| 251 | + } else { | |
| 252 | + [_kitCN.bgmPlayer resumeBgm]; | |
| 253 | + } | |
| 254 | +} | |
| 255 | + | |
| 256 | +- (void)bgmPlayerLast:(UIButton *)button { | |
| 257 | + /* | |
| 258 | + if (_currentIndex == 0) { | |
| 259 | + [self toast:@"已经是第一首"]; | |
| 260 | + } else { | |
| 261 | + _currentIndex --; | |
| 262 | + [_kitCN.bgmPlayer stopPlayBgm]; | |
| 263 | + [_kitCN.bgmPlayer startPlayBgm:[[NSBundle mainBundle] pathForResource:_listArr[_currentIndex] ofType:@"mp3"] isLoop:_playMode]; | |
| 264 | + _bgmPlayerView.songTitleLab.text = _listArr[_currentIndex]; | |
| 265 | + } | |
| 266 | + */ | |
| 267 | + | |
| 268 | + [_kitCN.streamerBase muteStream:button.selected]; | |
| 269 | +} | |
| 270 | + | |
| 271 | +- (void)bgmPlayerNext:(UIButton *)button; { | |
| 272 | + if (_currentIndex == 3) { | |
| 273 | + [self toast:@"已经是最后一首"]; | |
| 274 | + } else { | |
| 275 | + _currentIndex ++; | |
| 276 | + [_kitCN.bgmPlayer stopPlayBgm]; | |
| 277 | + [_kitCN.bgmPlayer startPlayBgm:[[NSBundle mainBundle] pathForResource:_listArr[_currentIndex] ofType:@"mp3"] isLoop:_playMode]; | |
| 278 | + _bgmPlayerView.songTitleLab.text = _listArr[_currentIndex]; | |
| 279 | + } | |
| 280 | +} | |
| 281 | + | |
| 282 | +- (void)bgmPlayerProgressSlider:(UISlider *)slider { | |
| 283 | + [_kitCN.bgmPlayer seekToProgress:slider.value]; | |
| 284 | +} | |
| 285 | + | |
| 286 | +#pragma mark - | |
| 287 | +#pragma mark - notification | |
| 288 | +- (void)addObservers | |
| 289 | +{ | |
| 290 | + [[NSNotificationCenter defaultCenter] addObserver:self | |
| 291 | + selector:@selector(streamStateChange) | |
| 292 | + name:CNLiveStreamerStateDidChangeNotification | |
| 293 | + object:nil]; | |
| 294 | +} | |
| 295 | + | |
| 296 | +- (void)streamStateChange | |
| 297 | +{ | |
| 298 | + | |
| 299 | + if (_kitCN.streamState == CNLiveStreamStateIdle) { | |
| 300 | + NSLog(@"---------CNLiveStreamStateIdle"); | |
| 301 | + _stateLab.text = @"CNLiveStreamStateIdle"; | |
| 302 | + } | |
| 303 | + | |
| 304 | + if (_kitCN.streamState == CNLiveStreamStateConnected) { | |
| 305 | + _startLiveBtn.selected = YES; | |
| 306 | + NSLog(@"---------CNLiveStreamStateConnected"); | |
| 307 | + _stateLab.text = [NSString stringWithFormat:@"CNLiveStreamStateConnected------%@",self.url]; | |
| 308 | + } | |
| 309 | + | |
| 310 | + if (_kitCN.streamState == CNLiveStreamStateConnecting) { | |
| 311 | + NSLog(@"---------CNLiveStreamStateConnecting"); | |
| 312 | + _stateLab.text = @"CNLiveStreamStateConnecting"; | |
| 313 | + } | |
| 314 | + | |
| 315 | + //推流出错 | |
| 316 | + if (_kitCN.streamState == CNLiveStreamStateError) { | |
| 317 | + NSLog(@"---------CNLiveStreamStateError"); | |
| 318 | + [self onStreamError]; | |
| 319 | + } | |
| 320 | + | |
| 321 | + //断开推流 | |
| 322 | + if ( _kitCN.streamState == CNLiveStreamStateDisconnecting) { | |
| 323 | + NSLog(@"---------CNLiveStreamStateDisconnecting"); | |
| 324 | + _stateLab.text = @"CNLiveStreamStateDisconnecting"; | |
| 325 | + | |
| 326 | + } | |
| 327 | + | |
| 328 | + //结束推流成功 | |
| 329 | + if ( _kitCN.streamState == CNLiveStopStreamSuccess) { | |
| 330 | + NSLog(@"---------CNLiveStopStreamSuccess"); | |
| 331 | + _stateLab.text = @"CNLiveStopStreamSuccess"; | |
| 332 | + | |
| 333 | + } | |
| 334 | +} | |
| 335 | + | |
| 336 | +- (void)onStreamError { | |
| 337 | + | |
| 338 | + _startLiveBtn.selected = NO; | |
| 339 | + CNLiveStreamErrorCode err = _kitCN.streamErrorCode; | |
| 340 | + [self toast:[NSString stringWithFormat:@"error ------ %lu",(unsigned long)err]]; | |
| 341 | + | |
| 342 | + NSLog(@"onErr: %lu [%@]", (unsigned long) err, _stateLab.text); | |
| 343 | + | |
| 344 | + if ( CNLiveStreamErrorCode_CNLiveAUTHFAILED == err ) { | |
| 345 | + _stateLab.text = @"SDK auth failed, \npls check ak/sk"; | |
| 346 | + } | |
| 347 | + else if ( CNLiveStreamErrorCode_CODEC_OPEN_FAILED == err) { | |
| 348 | + _stateLab.text = @"Selected Codec not supported \n in this version"; | |
| 349 | + } | |
| 350 | + else if ( CNLiveStreamErrorCode_CONNECT_FAILED == err) { | |
| 351 | + _stateLab.text = @"Connecting error, pls check host url \nor network"; | |
| 352 | + } | |
| 353 | + else if ( CNLiveStreamErrorCode_CONNECT_BREAK == err) { | |
| 354 | + _stateLab.text = @"Connection break"; | |
| 355 | + } | |
| 356 | + else if ( CNLiveStreamErrorCode_ABNORMAL == err) { | |
| 357 | + _stateLab.text = @"CNLiveStreamErrorCode_ABNORMAL"; | |
| 358 | + [self toast:@"推流异常中断~~"]; | |
| 359 | + | |
| 360 | + } else if (err == CNLiveStreamErrorCode_CODEC_OPEN_FAILED) { | |
| 361 | + NSLog(@"video codec open failed, try software codec"); | |
| 362 | + _kitCN.streamerBase.videoCodec = CNLiveVideoCodec_VT264; | |
| 363 | + [self tryReconnect]; | |
| 364 | + } | |
| 365 | + else { | |
| 366 | + | |
| 367 | + } | |
| 368 | + | |
| 369 | + // 断网重连 | |
| 370 | + if (err == CNLiveStreamErrorCode_CONNECT_BREAK || err == CNLiveStreamErrorCode_AV_SYNC_ERROR) { | |
| 371 | + [self tryReconnect]; | |
| 372 | + } | |
| 373 | + | |
| 374 | +} | |
| 375 | + | |
| 376 | +- (void) tryReconnect | |
| 377 | +{ | |
| 378 | + dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)); | |
| 379 | + dispatch_after(delay, dispatch_get_main_queue(), ^{ | |
| 380 | + | |
| 381 | + NSLog(@"try again"); | |
| 382 | + | |
| 383 | + [_kitCN stopStream]; | |
| 384 | + | |
| 385 | + if (_isAuthLive) { | |
| 386 | + | |
| 387 | + [_kitCN startStream:^{ | |
| 388 | + NSLog(@"开启推流成功 ------- success"); | |
| 389 | + _startLiveBtn.selected = YES; | |
| 390 | + | |
| 391 | + } failure:^(NSDictionary *errorDic) { | |
| 392 | + [self toast:errorDic[@"errorMessage"]]; | |
| 393 | + _startLiveBtn.selected = NO; | |
| 394 | + }]; | |
| 395 | + | |
| 396 | + }else{ | |
| 397 | + [_kitCN startStream:self.url]; | |
| 398 | + } | |
| 399 | + }); | |
| 400 | +} | |
| 401 | + | |
| 402 | +- (void)toast:(NSString*)message | |
| 403 | +{ | |
| 404 | + | |
| 405 | + UIAlertView *toast = [[UIAlertView alloc] initWithTitle:nil | |
| 406 | + message:message | |
| 407 | + delegate:nil | |
| 408 | + cancelButtonTitle:nil | |
| 409 | + otherButtonTitles:nil, nil]; | |
| 410 | + [toast show]; | |
| 411 | + double duration = 2.5; | |
| 412 | + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ | |
| 413 | + [toast dismissWithClickedButtonIndex:0 animated:NO]; | |
| 414 | + }); | |
| 415 | +} | |
| 416 | + | |
| 417 | +- (UILabel *)stateLab | |
| 418 | +{ | |
| 419 | + if (!_stateLab) { | |
| 420 | + _stateLab = [[UILabel alloc] initWithFrame:CGRectMake(0, Height-100, Width, 100)]; | |
| 421 | + _stateLab.backgroundColor = [UIColor colorWithWhite:0 alpha:0.1]; | |
| 422 | + _stateLab.numberOfLines = 0; | |
| 423 | + _stateLab.text = @"message"; | |
| 424 | + _stateLab.textColor = [UIColor redColor]; | |
| 425 | + } | |
| 426 | + return _stateLab; | |
| 427 | +} | |
| 428 | + | |
| 429 | +- (AudioCfgView *)audioCfgView | |
| 430 | +{ | |
| 431 | + if (!_audioCfgView) { | |
| 432 | + _audioCfgView = [[AudioCfgView alloc] initWithFrame:CGRectMake(0, 160, Width, 200)]; | |
| 433 | + _audioCfgView.hidden = YES; | |
| 434 | + } | |
| 435 | + return _audioCfgView; | |
| 436 | +} | |
| 437 | + | |
| 438 | +- (BgmPlayerView *)bgmPlayerView | |
| 439 | +{ | |
| 440 | + if (!_bgmPlayerView) { | |
| 441 | + _bgmPlayerView = [[BgmPlayerView alloc] initWithFrame:CGRectMake(0, 160, Width, 200)]; | |
| 442 | + _bgmPlayerView.delegate = self; | |
| 443 | + _bgmPlayerView.hidden = YES; | |
| 444 | + } | |
| 445 | + return _bgmPlayerView; | |
| 446 | +} | |
| 447 | + | |
| 448 | +- (void)dealloc | |
| 449 | +{ | |
| 450 | + if (_currentTimer) { | |
| 451 | + [_currentTimer invalidate]; | |
| 452 | + _currentTimer = nil; | |
| 453 | + } | |
| 454 | + | |
| 455 | + [_kitCN quitStreaming]; | |
| 456 | + self.kitCN = nil; | |
| 457 | + _bgmPlayerView.delegate = nil; | |
| 458 | + [[NSNotificationCenter defaultCenter] removeObserver:self]; | |
| 459 | +} | |
| 460 | + | |
| 461 | +- (void)didReceiveMemoryWarning { | |
| 462 | + [super didReceiveMemoryWarning]; | |
| 463 | + // Dispose of any resources that can be recreated. | |
| 464 | +} | |
| 465 | + | |
| 466 | +/* | |
| 467 | +#pragma mark - Navigation | |
| 468 | + | |
| 469 | +// In a storyboard-based application, you will often want to do a little preparation before navigation | |
| 470 | +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { | |
| 471 | + // Get the new view controller using [segue destinationViewController]. | |
| 472 | + // Pass the selected object to the new view controller. | |
| 473 | +} | |
| 474 | +*/ | |
| 475 | + | |
| 476 | +@end | ... | ... |
Example/CNLivePlayer/Streamer/BgmPlayerView.h
0 → 100644
| 1 | +// | |
| 2 | +// BgmPlayerView.h | |
| 3 | +// CNLivePlayerSDKDemo | |
| 4 | +// | |
| 5 | +// Created by iOS on 17/4/19. | |
| 6 | +// Copyright © 2017年 雷浩杰. All rights reserved. | |
| 7 | +// | |
| 8 | + | |
| 9 | +#import <UIKit/UIKit.h> | |
| 10 | + | |
| 11 | +@protocol BgmPlayerViewDelegate <NSObject> | |
| 12 | + | |
| 13 | +- (void)valueType:(BOOL)isVolume value:(float)value; | |
| 14 | +- (void)bgmPlayerPlay:(UIButton *)button; | |
| 15 | +- (void)bgmPlayerMode:(UIButton *)button; | |
| 16 | +- (void)bgmPlayerPauseOrResume:(UIButton *)button; | |
| 17 | +- (void)bgmPlayerLast:(UIButton *)button; | |
| 18 | +- (void)bgmPlayerNext:(UIButton *)button; | |
| 19 | +- (void)bgmPlayerProgressSlider:(UISlider *)slider; | |
| 20 | + | |
| 21 | +@end | |
| 22 | + | |
| 23 | +@interface BgmPlayerView : UIView | |
| 24 | + | |
| 25 | +@property (nonatomic, strong) UILabel *currentTimeLab; | |
| 26 | +@property (nonatomic, strong) UILabel *duraTimeLab; | |
| 27 | +@property (nonatomic, strong) UISlider *proSlider; | |
| 28 | +@property (nonatomic, strong) UILabel *songTitleLab; | |
| 29 | +@property (nonatomic, strong) UIButton *playBtn; | |
| 30 | +@property (nonatomic, strong) UIButton *nextBtn; | |
| 31 | +@property (nonatomic, strong) UIButton *lastBtn; | |
| 32 | +@property (nonatomic, strong) UIButton *pauseBtn; | |
| 33 | +@property (nonatomic, strong) UIButton *playModeBtn; | |
| 34 | +@property (nonatomic, assign) id<BgmPlayerViewDelegate> delegate; | |
| 35 | + | |
| 36 | +@end | |
| 37 | + | |
| 38 | +@interface MusicListView : UIView | |
| 39 | + | |
| 40 | +@end | ... | ... |
Example/CNLivePlayer/Streamer/BgmPlayerView.m
0 → 100644
| 1 | +// | |
| 2 | +// BgmPlayerView.m | |
| 3 | +// CNLivePlayerSDKDemo | |
| 4 | +// | |
| 5 | +// Created by iOS on 17/4/19. | |
| 6 | +// Copyright © 2017年 雷浩杰. All rights reserved. | |
| 7 | +// | |
| 8 | + | |
| 9 | +#import "BgmPlayerView.h" | |
| 10 | + | |
| 11 | +#define COLOR(R, G, B, A) [UIColor colorWithRed:R/255.0 green:G/255.0 blue:B/255.0 alpha:A] | |
| 12 | +#define UIColorFromRGB(rgbValue) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 green:((float)((rgbValue & 0xFF00) >> 8))/255.0 blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0] | |
| 13 | + | |
| 14 | +#define BTN_WIDTH (CGRectGetWidth(self.bounds)-SPACE*6)/5 | |
| 15 | +#define SPACE 7 | |
| 16 | + | |
| 17 | +@interface BgmPlayerView () | |
| 18 | + | |
| 19 | +@property (nonatomic, strong) UIView *playFuncView; | |
| 20 | +@property (nonatomic, strong) UIView *volumeFuncView; | |
| 21 | +@property (nonatomic, strong) UILabel *volumeValLab; | |
| 22 | +@property (nonatomic, strong) UILabel *toneValLab; | |
| 23 | + | |
| 24 | +@end | |
| 25 | + | |
| 26 | +@implementation BgmPlayerView | |
| 27 | + | |
| 28 | +- (instancetype)initWithFrame:(CGRect)frame | |
| 29 | +{ | |
| 30 | + self = [super initWithFrame:frame]; | |
| 31 | + if (self) { | |
| 32 | + | |
| 33 | + self.backgroundColor = [UIColor colorWithWhite:0 alpha:0.1]; | |
| 34 | + | |
| 35 | + [self addSubview:self.playFuncView]; | |
| 36 | + [self addSubview:self.volumeFuncView]; | |
| 37 | + [self addSubview:self.currentTimeLab]; | |
| 38 | + [self addSubview:self.duraTimeLab]; | |
| 39 | + [self addSubview:self.proSlider]; | |
| 40 | + [self addSubview:self.songTitleLab]; | |
| 41 | + | |
| 42 | + _playModeBtn = [self addButton:CGRectMake(SPACE, 0, BTN_WIDTH, 30) action:@selector(playModeBtnAction:) normalTitle:@"顺序播放" selectedTitle:@"循环播放"]; | |
| 43 | + _lastBtn = [self addButton:CGRectMake(BTN_WIDTH+2*SPACE, 0, BTN_WIDTH, 30) action:@selector(lastBtnAction:) normalTitle:@"上一首" selectedTitle:@"上一首"]; | |
| 44 | + _playBtn = [self addButton:CGRectMake(BTN_WIDTH*2+3*SPACE, 0, BTN_WIDTH, 30) action:@selector(playBtnAction:) normalTitle:@"播放" selectedTitle:@"停止"]; | |
| 45 | + _pauseBtn = [self addButton:CGRectMake(BTN_WIDTH*3+4*SPACE, 0, BTN_WIDTH, 30) action:@selector(pauseBtnAction:) normalTitle:@"暂停" selectedTitle:@"继续"]; | |
| 46 | + _nextBtn = [self addButton:CGRectMake(BTN_WIDTH*4+5*SPACE, 0, BTN_WIDTH, 30) action:@selector(nextBtnAction:) normalTitle:@"下一首" selectedTitle:@"下一首"]; | |
| 47 | + | |
| 48 | + [self.volumeFuncView addSubview:[self addVolumeView:CGRectMake(0, 0, CGRectGetWidth(self.bounds)/2, 40) action:@selector(volumeStepperAction:) type:YES]]; | |
| 49 | + [self.volumeFuncView addSubview:[self addVolumeView:CGRectMake(CGRectGetWidth(self.bounds)/2, 0, CGRectGetWidth(self.bounds), 40) action:@selector(toneStepperAction:) type:NO]]; | |
| 50 | + | |
| 51 | + | |
| 52 | + } | |
| 53 | + return self; | |
| 54 | +} | |
| 55 | + | |
| 56 | +#pragma mark - | |
| 57 | +#pragma mark - action | |
| 58 | +- (void)playModeBtnAction:(UIButton *)button { | |
| 59 | + button.selected = !button.selected; | |
| 60 | + if (self.delegate && [self.delegate respondsToSelector:@selector(bgmPlayerMode:)]) { | |
| 61 | + [self.delegate bgmPlayerMode:button]; | |
| 62 | + } | |
| 63 | +} | |
| 64 | + | |
| 65 | +- (void)lastBtnAction:(UIButton *)button { | |
| 66 | + button.selected = !button.selected; | |
| 67 | + if (self.delegate && [self.delegate respondsToSelector:@selector(bgmPlayerLast:)]) { | |
| 68 | + [self.delegate bgmPlayerLast:button]; | |
| 69 | + } | |
| 70 | +} | |
| 71 | + | |
| 72 | +- (void)playBtnAction:(UIButton *)button { | |
| 73 | + button.selected = !button.selected; | |
| 74 | + if (self.delegate && [self.delegate respondsToSelector:@selector(bgmPlayerPlay:)]) { | |
| 75 | + [self.delegate bgmPlayerPlay:button]; | |
| 76 | + } | |
| 77 | +} | |
| 78 | + | |
| 79 | +- (void)nextBtnAction:(UIButton *)button { | |
| 80 | + button.selected = !button.selected; | |
| 81 | + if (self.delegate && [self.delegate respondsToSelector:@selector(bgmPlayerNext:)]) { | |
| 82 | + [self.delegate bgmPlayerNext:button]; | |
| 83 | + } | |
| 84 | +} | |
| 85 | + | |
| 86 | +- (void)pauseBtnAction:(UIButton *)button { | |
| 87 | + button.selected = !button.selected; | |
| 88 | + if (self.delegate && [self.delegate respondsToSelector:@selector(bgmPlayerPauseOrResume:)]) { | |
| 89 | + [self.delegate bgmPlayerPauseOrResume:button]; | |
| 90 | + } | |
| 91 | +} | |
| 92 | + | |
| 93 | +- (void)beginScrubbing { | |
| 94 | +} | |
| 95 | + | |
| 96 | +- (void)endScrubbing:(UISlider *)slider { | |
| 97 | + if (self.delegate && [self.delegate respondsToSelector:@selector(bgmPlayerProgressSlider:)]) { | |
| 98 | + [self.delegate bgmPlayerProgressSlider:slider]; | |
| 99 | + } | |
| 100 | +} | |
| 101 | + | |
| 102 | +- (void)volumeStepperAction:(UIStepper *)stepper { | |
| 103 | + _volumeValLab.text = [NSString stringWithFormat:@"%.1f",stepper.value]; | |
| 104 | + if (self.delegate && [self.delegate respondsToSelector:@selector(valueType:value:)]) { | |
| 105 | + [self.delegate valueType:YES value:stepper.value]; | |
| 106 | + } | |
| 107 | +} | |
| 108 | + | |
| 109 | +- (void)toneStepperAction:(UIStepper *)stepper { | |
| 110 | + _toneValLab.text = [NSString stringWithFormat:@"%.1f",stepper.value]; | |
| 111 | + if (self.delegate && [self.delegate respondsToSelector:@selector(valueType:value:)]) { | |
| 112 | + [self.delegate valueType:NO value:stepper.value]; | |
| 113 | + } | |
| 114 | +} | |
| 115 | + | |
| 116 | +#pragma mark - | |
| 117 | +#pragma mark - | |
| 118 | +- (UIButton *)addButton:(CGRect)rect action:(SEL)action normalTitle:(NSString *)normalTitle selectedTitle:(NSString *)selectedTitle{ | |
| 119 | + UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; | |
| 120 | + button.frame = rect; | |
| 121 | + [button addTarget:self action:action forControlEvents:UIControlEventTouchUpInside]; | |
| 122 | + [button setTitle:normalTitle forState:UIControlStateNormal]; | |
| 123 | + [button setTitle:selectedTitle forState:UIControlStateSelected]; | |
| 124 | + [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; | |
| 125 | + button.titleLabel.font = [UIFont systemFontOfSize:14]; | |
| 126 | + button.layer.cornerRadius = 5; | |
| 127 | + button.layer.masksToBounds = YES; | |
| 128 | + button.layer.borderColor = [UIColor blackColor].CGColor; | |
| 129 | + button.layer.borderWidth = 1; | |
| 130 | + [self.playFuncView addSubview:button]; | |
| 131 | + return button; | |
| 132 | +} | |
| 133 | + | |
| 134 | +- (UIView *)addVolumeView:(CGRect)rect action:(SEL)action type:(BOOL)volume { | |
| 135 | + UIView *view = [[UIView alloc] initWithFrame:rect]; | |
| 136 | + UILabel *titleLab = [[UILabel alloc] initWithFrame:CGRectMake(0, 10, 40, 20)]; | |
| 137 | + | |
| 138 | + UILabel *valueLab = [[UILabel alloc] initWithFrame:CGRectMake(45, 10, 30, 20)]; | |
| 139 | + valueLab.font = [UIFont systemFontOfSize:14]; | |
| 140 | + | |
| 141 | + UIStepper *step = [[UIStepper alloc] initWithFrame:CGRectMake(80, 5, 30, 30)]; | |
| 142 | + step.tintColor = [UIColor blackColor]; | |
| 143 | + [step addTarget:self action:action forControlEvents:UIControlEventValueChanged]; | |
| 144 | + | |
| 145 | + if (volume) { | |
| 146 | + titleLab.text = @"音量: "; | |
| 147 | + valueLab.text = @"1.0"; | |
| 148 | + _volumeValLab = valueLab; | |
| 149 | + step.maximumValue = 1; | |
| 150 | + step.minimumValue = 0; | |
| 151 | + step.stepValue = 0.1; | |
| 152 | + step.value = 1.0; | |
| 153 | + } else { | |
| 154 | + titleLab.text = @"音调: "; | |
| 155 | + valueLab.text = @"0.01"; | |
| 156 | + _toneValLab = valueLab; | |
| 157 | + step.maximumValue = 24.0; | |
| 158 | + step.minimumValue = -24.0; | |
| 159 | + step.stepValue = 1.0; | |
| 160 | + step.value = 0.01; | |
| 161 | + } | |
| 162 | + | |
| 163 | + [view addSubview:titleLab]; | |
| 164 | + [view addSubview:valueLab]; | |
| 165 | + [view addSubview:step]; | |
| 166 | + return view; | |
| 167 | +} | |
| 168 | + | |
| 169 | +#pragma mark - | |
| 170 | +#pragma mark - gatter | |
| 171 | +- (UIView *)playFuncView { | |
| 172 | + if (!_playFuncView) { | |
| 173 | + _playFuncView = [[UIView alloc] initWithFrame:CGRectMake(0, 80, CGRectGetWidth(self.bounds), 40)]; | |
| 174 | + } | |
| 175 | + return _playFuncView; | |
| 176 | +} | |
| 177 | + | |
| 178 | +- (UIView *)volumeFuncView { | |
| 179 | + if (!_volumeFuncView) { | |
| 180 | + _volumeFuncView = [[UIView alloc] initWithFrame:CGRectMake(0, 120, CGRectGetWidth(self.bounds), 40)]; | |
| 181 | + } | |
| 182 | + return _volumeFuncView; | |
| 183 | +} | |
| 184 | + | |
| 185 | + | |
| 186 | +- (UILabel *)songTitleLab | |
| 187 | +{ | |
| 188 | + if (!_songTitleLab) { | |
| 189 | + _songTitleLab = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, CGRectGetWidth(self.bounds)-20, 20)]; | |
| 190 | + _songTitleLab.textColor = [UIColor redColor]; | |
| 191 | + _songTitleLab.font = [UIFont systemFontOfSize:14]; | |
| 192 | + _songTitleLab.text = @"xxxx"; | |
| 193 | + } | |
| 194 | + return _songTitleLab; | |
| 195 | +} | |
| 196 | + | |
| 197 | +- (UILabel *)currentTimeLab | |
| 198 | +{ | |
| 199 | + if (!_currentTimeLab) { | |
| 200 | + _currentTimeLab = [[UILabel alloc] initWithFrame:CGRectMake(10, 40, 40, 20)]; | |
| 201 | + _currentTimeLab.font = [UIFont systemFontOfSize:13]; | |
| 202 | + _currentTimeLab.text = @"00:00"; | |
| 203 | + } | |
| 204 | + return _currentTimeLab; | |
| 205 | +} | |
| 206 | + | |
| 207 | +- (UILabel *)duraTimeLab | |
| 208 | +{ | |
| 209 | + if (!_duraTimeLab) { | |
| 210 | + _duraTimeLab = [[UILabel alloc] initWithFrame:CGRectMake(CGRectGetWidth(self.bounds)-50, 40, 40, 20)]; | |
| 211 | + _duraTimeLab.font = [UIFont systemFontOfSize:13]; | |
| 212 | + _duraTimeLab.text = @"00:00"; | |
| 213 | + } | |
| 214 | + return _duraTimeLab; | |
| 215 | +} | |
| 216 | + | |
| 217 | +- (UISlider *)proSlider | |
| 218 | +{ | |
| 219 | + if (!_proSlider) { | |
| 220 | + _proSlider = [[UISlider alloc] initWithFrame:CGRectMake(60, 35, CGRectGetWidth(self.bounds)-120, 30)]; | |
| 221 | + [_proSlider setThumbImage:[UIImage imageNamed:@"btn_dot"] forState:UIControlStateNormal]; | |
| 222 | + [_proSlider setMinimumTrackTintColor:[UIColor redColor]]; | |
| 223 | + [_proSlider setMaximumTrackTintColor:[UIColor whiteColor]]; | |
| 224 | + [_proSlider addTarget:self action:@selector(beginScrubbing) forControlEvents:UIControlEventTouchDown]; | |
| 225 | + [_proSlider addTarget:self action:@selector(endScrubbing:) forControlEvents:UIControlEventTouchUpInside]; | |
| 226 | + [_proSlider addTarget:self action:@selector(endScrubbing:) forControlEvents:UIControlEventTouchUpOutside]; | |
| 227 | + } | |
| 228 | + return _proSlider; | |
| 229 | +} | |
| 230 | +/* | |
| 231 | +// Only override drawRect: if you perform custom drawing. | |
| 232 | +// An empty implementation adversely affects performance during animation. | |
| 233 | +- (void)drawRect:(CGRect)rect { | |
| 234 | + // Drawing code | |
| 235 | +} | |
| 236 | +*/ | |
| 237 | + | |
| 238 | +@end | |
| 239 | + | |
| 240 | +#pragma mark - 音乐列表 | |
| 241 | + | |
| 242 | +@interface MusicListView ()<UITableViewDelegate,UITableViewDataSource> | |
| 243 | +{ | |
| 244 | + NSArray *_listArr; | |
| 245 | +} | |
| 246 | + | |
| 247 | +@property (nonatomic, strong) UITableView *tableView; | |
| 248 | + | |
| 249 | +@end | |
| 250 | + | |
| 251 | +@implementation MusicListView | |
| 252 | + | |
| 253 | +- (instancetype)initWithFrame:(CGRect)frame | |
| 254 | +{ | |
| 255 | + self = [super initWithFrame:frame]; | |
| 256 | + if (self) { | |
| 257 | + _listArr = @[@"See You Again .mp3", | |
| 258 | + @"Idina Menzel - Let It Go.mp3", | |
| 259 | + @"Morrie - Lullaby.mp3", | |
| 260 | + @"Zedd,Alessia Cara - Stay.mp3"]; | |
| 261 | + } | |
| 262 | + return self; | |
| 263 | +} | |
| 264 | + | |
| 265 | +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { | |
| 266 | + return _listArr.count; | |
| 267 | +} | |
| 268 | + | |
| 269 | +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { | |
| 270 | + static NSString *cellID = @"MusicListViewIdentify"; | |
| 271 | + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID]; | |
| 272 | + if (!cell) { | |
| 273 | + cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID]; | |
| 274 | + } | |
| 275 | + cell.textLabel.text = _listArr[indexPath.row]; | |
| 276 | + cell.textLabel.textColor = UIColorFromRGB(515151); | |
| 277 | + cell.backgroundColor = [UIColor whiteColor]; | |
| 278 | + return cell; | |
| 279 | +} | |
| 280 | + | |
| 281 | + | |
| 282 | +- (UITableView *)tableView | |
| 283 | +{ | |
| 284 | + if (!_tableView) { | |
| 285 | + _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 40, CGRectGetWidth(self.bounds), 100) style:UITableViewStylePlain]; | |
| 286 | + _tableView.delegate = self; | |
| 287 | + _tableView.dataSource = self; | |
| 288 | + _tableView.backgroundColor = [UIColor whiteColor]; | |
| 289 | + } | |
| 290 | + return _tableView; | |
| 291 | +} | |
| 292 | + | |
| 293 | + | |
| 294 | +@end | ... | ... |
Example/CNLivePlayer/CNLiveStreamerController.h renamed to Example/CNLivePlayer/Streamer/CNLiveStreamerController.h
| 1 | 1 | // |
| 2 | -// CNLiveStreamerController.h | |
| 3 | -// CNLivePlayer_Example | |
| 2 | +// StreamerViewController.h | |
| 3 | +// CNLivePlayerSDKTest | |
| 4 | 4 | // |
| 5 | -// Created by CNLive-zxw on 2019/8/21. | |
| 6 | -// Copyright © 2019 153993236@qq.com. All rights reserved. | |
| 5 | +// Created by 雷浩杰 on 16/8/10. | |
| 6 | +// Copyright © 2016年 雷浩杰. All rights reserved. | |
| 7 | 7 | // |
| 8 | 8 | |
| 9 | 9 | #import <UIKit/UIKit.h> |
| 10 | 10 | |
| 11 | -NS_ASSUME_NONNULL_BEGIN | |
| 12 | - | |
| 13 | 11 | @interface CNLiveStreamerController : UIViewController |
| 14 | 12 | |
| 15 | 13 | @end |
| 16 | - | |
| 17 | -NS_ASSUME_NONNULL_END | ... | ... |
Example/CNLivePlayer/Streamer/CNLiveStreamerController.m
0 → 100644
| 1 | +// | |
| 2 | +// StreamerViewController.m | |
| 3 | +// CNLivePlayerSDKTest | |
| 4 | +// | |
| 5 | +// Created by 雷浩杰 on 16/8/10. | |
| 6 | +// Copyright © 2016年 雷浩杰. All rights reserved. | |
| 7 | +// | |
| 8 | + | |
| 9 | +#import "CNLiveStreamerController.h" | |
| 10 | +#import "StreamerDetailViewController.h" | |
| 11 | +#import "AudioStreamingViewController.h" | |
| 12 | + | |
| 13 | +#define KScreenWidth [UIScreen mainScreen].bounds.size.width | |
| 14 | +#define KScreenHeight [UIScreen mainScreen].bounds.size.height | |
| 15 | + | |
| 16 | +@interface CNLiveStreamerController ()<UITextFieldDelegate> | |
| 17 | +@property (nonatomic, strong) UITextField *urlTextField; | |
| 18 | +@property (nonatomic, strong) UISwitch *pureAudioSwitch; | |
| 19 | +@property (nonatomic, strong) UISegmentedControl *liveType; | |
| 20 | + | |
| 21 | +@end | |
| 22 | + | |
| 23 | +@implementation CNLiveStreamerController | |
| 24 | + | |
| 25 | +- (void)viewDidLoad { | |
| 26 | + [super viewDidLoad]; | |
| 27 | + self.view.backgroundColor = [UIColor whiteColor]; | |
| 28 | + | |
| 29 | + [self.view addSubview:self.urlTextField]; | |
| 30 | + [self.view addSubview:self.pureAudioSwitch]; | |
| 31 | + [self.view addSubview:self.liveType]; | |
| 32 | + | |
| 33 | + UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom]; | |
| 34 | + btn.frame = CGRectMake(0, 0, 100, 50); | |
| 35 | + btn.center = CGPointMake(self.view.center.x, self.view.center.y); | |
| 36 | + btn.backgroundColor = [UIColor redColor]; | |
| 37 | + [btn setTitle:@"返回" forState:UIControlStateNormal]; | |
| 38 | + [btn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; | |
| 39 | + [btn addTarget:self action:@selector(btnDidClicked) forControlEvents:UIControlEventTouchUpInside]; | |
| 40 | + [self.view addSubview:btn]; | |
| 41 | + | |
| 42 | +} | |
| 43 | + | |
| 44 | +- (void)btnDidClicked{ | |
| 45 | + [self dismissViewControllerAnimated:YES completion:nil]; | |
| 46 | + | |
| 47 | +} | |
| 48 | + | |
| 49 | +#pragma mark - Actioon | |
| 50 | +- (void)onSegmentedControl:(UISegmentedControl *)sender { | |
| 51 | + if (sender.selectedSegmentIndex == 0) { | |
| 52 | + if (_urlTextField.text.length == 0) { | |
| 53 | + [self toast:@"请输入推流地址"]; | |
| 54 | + | |
| 55 | + } | |
| 56 | + else{ | |
| 57 | + if (_pureAudioSwitch.on) { | |
| 58 | + AudioStreamingViewController *vc = [[AudioStreamingViewController alloc] init]; | |
| 59 | + vc.isAuthLive = NO; | |
| 60 | + vc.url = [NSURL URLWithString:[NSString stringWithFormat:@"%@",self.urlTextField.text]]; | |
| 61 | + [self presentViewController:vc animated:YES completion:NULL]; | |
| 62 | + } | |
| 63 | + else { | |
| 64 | + StreamerDetailViewController *vc = [[StreamerDetailViewController alloc] init]; | |
| 65 | + vc.isAuthLive = NO; | |
| 66 | + vc.url = [NSURL URLWithString:[NSString stringWithFormat:@"%@",self.urlTextField.text]]; | |
| 67 | + [self presentViewController:vc animated:YES completion:NULL]; | |
| 68 | + } | |
| 69 | + } | |
| 70 | + | |
| 71 | + } | |
| 72 | + else if (sender.selectedSegmentIndex == 1) { | |
| 73 | + | |
| 74 | + if (_pureAudioSwitch.on) { | |
| 75 | + AudioStreamingViewController *vc = [[AudioStreamingViewController alloc] init]; | |
| 76 | + vc.isAuthLive = YES; | |
| 77 | + [self presentViewController:vc animated:YES completion:NULL]; | |
| 78 | + } | |
| 79 | + else { | |
| 80 | + StreamerDetailViewController *vc = [[StreamerDetailViewController alloc] init]; | |
| 81 | + vc.isAuthLive = YES; | |
| 82 | + vc.url = [NSURL URLWithString:[NSString stringWithFormat:@"%@",self.urlTextField.text]]; | |
| 83 | + [self presentViewController:vc animated:YES completion:NULL]; | |
| 84 | + } | |
| 85 | + | |
| 86 | + } | |
| 87 | + else if (sender.selectedSegmentIndex == 2) { | |
| 88 | + StreamerDetailViewController *vc = [[StreamerDetailViewController alloc] init]; | |
| 89 | + vc.isRecord = YES; | |
| 90 | + [self presentViewController:vc animated:YES completion:NULL]; | |
| 91 | + | |
| 92 | + } | |
| 93 | + | |
| 94 | + _liveType.selectedSegmentIndex = -1; | |
| 95 | + | |
| 96 | +} | |
| 97 | + | |
| 98 | + | |
| 99 | +- (void)toast:(NSString*)message { | |
| 100 | + UIAlertView *toast = [[UIAlertView alloc] initWithTitle:nil | |
| 101 | + message:message | |
| 102 | + delegate:nil | |
| 103 | + cancelButtonTitle:nil | |
| 104 | + otherButtonTitles:nil, nil]; | |
| 105 | + [toast show]; | |
| 106 | + double duration = 2.5; | |
| 107 | + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ | |
| 108 | + [toast dismissWithClickedButtonIndex:0 animated:NO]; | |
| 109 | + }); | |
| 110 | +} | |
| 111 | + | |
| 112 | +- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { | |
| 113 | + if ([_urlTextField isFirstResponder]) { | |
| 114 | + [_urlTextField resignFirstResponder]; | |
| 115 | + } | |
| 116 | +} | |
| 117 | + | |
| 118 | +- (BOOL)textFieldShouldReturn:(UITextField *)textField { | |
| 119 | + [textField resignFirstResponder]; | |
| 120 | + return YES; | |
| 121 | +} | |
| 122 | + | |
| 123 | +#pragma mark - getter | |
| 124 | +- (UITextField *)urlTextField { | |
| 125 | + if (!_urlTextField) { | |
| 126 | + _urlTextField = [[UITextField alloc] initWithFrame:CGRectMake(10, 170, KScreenWidth-20, 40)]; | |
| 127 | + _urlTextField.placeholder = @"请输入推流地址"; | |
| 128 | + _urlTextField.borderStyle = UITextBorderStyleRoundedRect; | |
| 129 | + _urlTextField.returnKeyType = UIReturnKeyDone; | |
| 130 | + _urlTextField.clearButtonMode = UITextFieldViewModeWhileEditing; | |
| 131 | + _urlTextField.delegate = self; | |
| 132 | + _urlTextField.text = @"rtmp://jsrtmp.up.cnlive.com/live/ceshi"; | |
| 133 | + UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, -30, 80, 30)]; | |
| 134 | + label.text = @"推流地址:"; | |
| 135 | + label.font = [UIFont systemFontOfSize:15]; | |
| 136 | + [_urlTextField addSubview:label]; | |
| 137 | + } | |
| 138 | + return _urlTextField; | |
| 139 | +} | |
| 140 | + | |
| 141 | +- (UISwitch *)pureAudioSwitch { | |
| 142 | + if (!_pureAudioSwitch) { | |
| 143 | + _pureAudioSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(110, 85, 100, 30)]; | |
| 144 | + UILabel *modeLab = [[UILabel alloc] initWithFrame:CGRectMake(10, 90, 100, 20)]; | |
| 145 | + modeLab.textColor = [UIColor blackColor]; | |
| 146 | + modeLab.text = @"纯音频推流"; | |
| 147 | + [self.view addSubview:modeLab]; | |
| 148 | + } | |
| 149 | + return _pureAudioSwitch; | |
| 150 | +} | |
| 151 | + | |
| 152 | +- (UISegmentedControl *)liveType { | |
| 153 | + if (!_liveType) { | |
| 154 | + NSArray *items = @[ @"普通直播", | |
| 155 | + @"鉴权直播", | |
| 156 | + @"本地录制"]; | |
| 157 | + | |
| 158 | + _liveType = [[UISegmentedControl alloc] initWithItems:items]; | |
| 159 | + _liveType.frame = CGRectMake(10, self.view.bounds.size.height-80, self.view.bounds.size.width-20, 40); | |
| 160 | + _liveType.tintColor= [UIColor blackColor]; | |
| 161 | + _liveType.selectedSegmentIndex = 0; | |
| 162 | + _liveType.layer.cornerRadius = 5; | |
| 163 | + _liveType.selectedSegmentIndex = -1; | |
| 164 | + [_liveType addTarget:self action:@selector(onSegmentedControl:) forControlEvents:UIControlEventValueChanged]; | |
| 165 | + } | |
| 166 | + return _liveType; | |
| 167 | +} | |
| 168 | + | |
| 169 | + | |
| 170 | +@end | ... | ... |
Example/CNLivePlayer/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 | +typedef void(^FilterCurrentType)(NSInteger currentType); | |
| 13 | +typedef void(^FilterCurrentIdx)(NSInteger currentIdx); | |
| 14 | + | |
| 15 | +@interface FilterFunctionView : UIView | |
| 16 | + | |
| 17 | +@property (nonatomic, copy) FilterViewBlock filterViewBlock; | |
| 18 | +@property (nonatomic, copy) FilterCurrentType currentTypeBlock; | |
| 19 | +@property (nonatomic, copy) FilterCurrentIdx currentIdxBlock; | |
| 20 | + | |
| 21 | +@end | |
| 22 | + | ... | ... |
Example/CNLivePlayer/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 | ... | ... |
Example/CNLivePlayer/Streamer/FloatingViewController.h
0 → 100644
| 1 | +// | |
| 2 | +// FloatingViewController.h | |
| 3 | +// CNLivePlayerSDKDemo | |
| 4 | +// | |
| 5 | +// Created by iOS on 2017/9/20. | |
| 6 | +// Copyright © 2017年 雷浩杰. All rights reserved. | |
| 7 | +// | |
| 8 | + | |
| 9 | +#import <UIKit/UIKit.h> | |
| 10 | +#import "CNLiveStreamerKit.h" | |
| 11 | + | |
| 12 | +@interface FloatingViewController : UIViewController | |
| 13 | + | |
| 14 | +@property (nonatomic, strong) CNLiveStreamerKit *kit; | |
| 15 | + | |
| 16 | +@end | ... | ... |
Example/CNLivePlayer/Streamer/FloatingViewController.m
0 → 100644
| 1 | +// | |
| 2 | +// FloatingViewController.m | |
| 3 | +// CNLivePlayerSDKDemo | |
| 4 | +// | |
| 5 | +// Created by iOS on 2017/9/20. | |
| 6 | +// Copyright © 2017年 雷浩杰. All rights reserved. | |
| 7 | +// | |
| 8 | + | |
| 9 | +#import "FloatingViewController.h" | |
| 10 | + | |
| 11 | +#define Width [UIScreen mainScreen].bounds.size.width | |
| 12 | +#define Height [UIScreen mainScreen].bounds.size.height | |
| 13 | + | |
| 14 | +@interface FloatingViewController () | |
| 15 | + | |
| 16 | +@property (nonatomic, strong) UIView *preView; | |
| 17 | +@property CGPoint loc_in; | |
| 18 | + | |
| 19 | +@end | |
| 20 | + | |
| 21 | +@implementation FloatingViewController | |
| 22 | + | |
| 23 | +- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { | |
| 24 | + | |
| 25 | + [self.preView removeFromSuperview]; | |
| 26 | + self.preView = nil; | |
| 27 | + | |
| 28 | + self.preView = [self.kit floatingWindowFrame:CGRectMake(Width/3*2, Height/3*2, Width/3, Height/3)]; | |
| 29 | + [self.view addSubview:self.preView]; | |
| 30 | + UIPanGestureRecognizer *panGes = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)]; | |
| 31 | + [_preView addGestureRecognizer:panGes]; | |
| 32 | + | |
| 33 | +} | |
| 34 | + | |
| 35 | +- (void)viewDidLoad { | |
| 36 | + [super viewDidLoad]; | |
| 37 | + | |
| 38 | + self.view.backgroundColor = [UIColor whiteColor]; | |
| 39 | + | |
| 40 | + _preView = [self.kit floatingWindowFrame:CGRectMake(Width/3*2, Height/3*2, Width/3, Height/3)]; | |
| 41 | + [self.view addSubview:self.preView]; | |
| 42 | + UIPanGestureRecognizer *panGes = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)]; | |
| 43 | + [_preView addGestureRecognizer:panGes]; | |
| 44 | + | |
| 45 | + UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; | |
| 46 | + button.frame = CGRectMake(10, 30, 25, 25); | |
| 47 | + [button setImage:[UIImage imageNamed:@"back"] forState:UIControlStateNormal]; | |
| 48 | + [button addTarget:self action:@selector(backAction) forControlEvents:UIControlEventTouchUpInside]; | |
| 49 | + [self.view addSubview:button]; | |
| 50 | + | |
| 51 | +} | |
| 52 | + | |
| 53 | +- (void)backAction { | |
| 54 | + [self dismissViewControllerAnimated:YES completion:NULL]; | |
| 55 | +} | |
| 56 | + | |
| 57 | +- (void)pan:(UIPanGestureRecognizer *)ges{ | |
| 58 | + CGPoint loc = [ges locationInView:self.view]; | |
| 59 | + if (ges.state == UIGestureRecognizerStateBegan) { | |
| 60 | + _loc_in = [ges locationInView:_preView]; | |
| 61 | + } | |
| 62 | + | |
| 63 | + CGFloat x; | |
| 64 | + CGFloat y; | |
| 65 | + if (_preView.frame.size.width - _loc_in.x + loc.x >= Width){ | |
| 66 | + x = Width - _preView.frame.size.width * 0.5; | |
| 67 | + }else if (loc.x - _loc_in.x <= 0) { | |
| 68 | + x = _preView.frame.size.width * 0.5; | |
| 69 | + }else { | |
| 70 | + x = _preView.frame.size.width * 0.5 - _loc_in.x + loc.x; | |
| 71 | + } | |
| 72 | + | |
| 73 | + if (_preView.frame.size.height - _loc_in.y + loc.y >= Height) { | |
| 74 | + y = Height - _preView.frame.size.height * 0.5; | |
| 75 | + }else if (loc.y - _loc_in.y <= 0){ | |
| 76 | + y = _preView.frame.size.height * 0.5; | |
| 77 | + }else { | |
| 78 | + y = _preView.frame.size.height * 0.5 - _loc_in.y + loc.y; | |
| 79 | + } | |
| 80 | + | |
| 81 | + [UIView animateWithDuration:0 animations:^{ | |
| 82 | + _preView.center = CGPointMake(x, y); | |
| 83 | + }]; | |
| 84 | +} | |
| 85 | + | |
| 86 | + | |
| 87 | +- (void)didReceiveMemoryWarning { | |
| 88 | + [super didReceiveMemoryWarning]; | |
| 89 | + // Dispose of any resources that can be recreated. | |
| 90 | +} | |
| 91 | + | |
| 92 | +/* | |
| 93 | +#pragma mark - Navigation | |
| 94 | + | |
| 95 | +// In a storyboard-based application, you will often want to do a little preparation before navigation | |
| 96 | +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { | |
| 97 | + // Get the new view controller using [segue destinationViewController]. | |
| 98 | + // Pass the selected object to the new view controller. | |
| 99 | +} | |
| 100 | +*/ | |
| 101 | + | |
| 102 | +@end | ... | ... |
Example/CNLivePlayer/Streamer/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 | +typedef NS_ENUM(NSUInteger, LoadingViewStyle) { | |
| 12 | + LoadingViewStyleStartLoading = 0, | |
| 13 | + LoadingViewStyleStopLoading, | |
| 14 | + LoadingViewStyleRetry, | |
| 15 | +}; | |
| 16 | + | |
| 17 | +@class LoadingView; | |
| 18 | + | |
| 19 | +@protocol LoadingViewDelegate <NSObject> | |
| 20 | + | |
| 21 | +- (void)loadingView:(LoadingView *)loadingViewRetryAction; | |
| 22 | + | |
| 23 | +@end | |
| 24 | + | |
| 25 | +@interface LoadingView : UIView | |
| 26 | + | |
| 27 | +@property (nonatomic, assign) id<LoadingViewDelegate> delegate; | |
| 28 | + | |
| 29 | +- (void)setLoadingViewStyle:(LoadingViewStyle)style; | |
| 30 | + | |
| 31 | +@end | ... | ... |
Example/CNLivePlayer/Streamer/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 | +@property (nonatomic, strong) UIButton *retryBtn; | |
| 15 | + | |
| 16 | +@end | |
| 17 | + | |
| 18 | +@implementation LoadingView | |
| 19 | + | |
| 20 | +- (instancetype)initWithFrame:(CGRect)frame | |
| 21 | +{ | |
| 22 | + self = [super initWithFrame:frame]; | |
| 23 | + if (self) { | |
| 24 | + [self addSubview:self.activityIndicator]; | |
| 25 | + [self addSubview:self.retryBtn]; | |
| 26 | + [self.activityIndicator startAnimating]; | |
| 27 | + | |
| 28 | + } | |
| 29 | + return self; | |
| 30 | +} | |
| 31 | + | |
| 32 | +#pragma mark - | |
| 33 | +#pragma mark - action | |
| 34 | +- (void)retryBtnAction { | |
| 35 | + if (self.delegate && [self.delegate respondsToSelector:@selector(loadingView:)]) { | |
| 36 | + [self.delegate loadingView:self]; | |
| 37 | + [self setLoadingViewStyle:LoadingViewStyleStartLoading]; | |
| 38 | + } | |
| 39 | +} | |
| 40 | + | |
| 41 | +- (void)setLoadingViewStyle:(LoadingViewStyle)style { | |
| 42 | + switch (style) { | |
| 43 | + case LoadingViewStyleStartLoading: | |
| 44 | + [_activityIndicator startAnimating]; | |
| 45 | + _retryBtn.hidden = YES; | |
| 46 | + break; | |
| 47 | + | |
| 48 | + case LoadingViewStyleStopLoading: | |
| 49 | + [_activityIndicator stopAnimating]; | |
| 50 | + _retryBtn.hidden = YES; | |
| 51 | + break; | |
| 52 | + | |
| 53 | + case LoadingViewStyleRetry: | |
| 54 | + [_activityIndicator stopAnimating]; | |
| 55 | + _retryBtn.hidden = NO; | |
| 56 | + break; | |
| 57 | + | |
| 58 | + default: | |
| 59 | + break; | |
| 60 | + } | |
| 61 | +} | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | +#pragma mark - | |
| 66 | +#pragma mark - getter | |
| 67 | +- (UIActivityIndicatorView *)activityIndicator { | |
| 68 | + if (!_activityIndicator) { | |
| 69 | + _activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; | |
| 70 | + _activityIndicator.center = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2); | |
| 71 | + } | |
| 72 | + return _activityIndicator; | |
| 73 | +} | |
| 74 | + | |
| 75 | +- (UIButton *)retryBtn { | |
| 76 | + if (!_retryBtn) { | |
| 77 | + _retryBtn = [UIButton buttonWithType:UIButtonTypeCustom]; | |
| 78 | + _retryBtn.frame = CGRectMake(self.bounds.size.width/2-30, self.bounds.size.height/2-20, 60, 40); | |
| 79 | + [_retryBtn setTitle:@"重试" forState:UIControlStateNormal]; | |
| 80 | + [_retryBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; | |
| 81 | + _retryBtn.hidden = YES; | |
| 82 | + _retryBtn.layer.cornerRadius = 10; | |
| 83 | + _retryBtn.layer.masksToBounds = YES; | |
| 84 | + _retryBtn.layer.borderColor = [UIColor blackColor].CGColor; | |
| 85 | + _retryBtn.layer.borderWidth = 1; | |
| 86 | + [_retryBtn addTarget:self action:@selector(retryBtnAction) forControlEvents:UIControlEventTouchUpInside]; | |
| 87 | + | |
| 88 | + } | |
| 89 | + return _retryBtn; | |
| 90 | +} | |
| 91 | + | |
| 92 | +@end | ... | ... |
Example/CNLivePlayer/Streamer/MoreFunctionsView.h
0 → 100644
| 1 | +// | |
| 2 | +// MoreFunctionsView.h | |
| 3 | +// CNLivePlayerSDKDemo | |
| 4 | +// | |
| 5 | +// Created by iOS on 2017/9/19. | |
| 6 | +// Copyright © 2017年 雷浩杰. All rights reserved. | |
| 7 | +// | |
| 8 | + | |
| 9 | +#import <UIKit/UIKit.h> | |
| 10 | + | |
| 11 | +typedef NS_ENUM(NSUInteger, MoreFuncType) { | |
| 12 | + MoreFuncTypeScreenshot = 0, | |
| 13 | + MoreFuncTypeLiveScene, | |
| 14 | + MoreFuncTypeRecordScene, | |
| 15 | + MoreFuncTypeLogo | |
| 16 | +}; | |
| 17 | + | |
| 18 | +typedef void(^MoreFuncBlock)(MoreFuncType type, NSInteger idx, UISegmentedControl *seg); | |
| 19 | + | |
| 20 | +@interface MoreFunctionsView : UIView | |
| 21 | + | |
| 22 | +@property (nonatomic, copy) MoreFuncBlock moreFuncBlock; | |
| 23 | +@property (nonatomic, strong) UISwitch *bypassRecord; | |
| 24 | +@property (nonatomic, strong) UIButton *floatingWindowBtn; | |
| 25 | + | |
| 26 | +@end | ... | ... |
Example/CNLivePlayer/Streamer/MoreFunctionsView.m
0 → 100644
| 1 | +// | |
| 2 | +// MoreFunctionsView.m | |
| 3 | +// CNLivePlayerSDKDemo | |
| 4 | +// | |
| 5 | +// Created by iOS on 2017/9/19. | |
| 6 | +// Copyright © 2017年 雷浩杰. All rights reserved. | |
| 7 | +// | |
| 8 | + | |
| 9 | +#import "MoreFunctionsView.h" | |
| 10 | + | |
| 11 | +@interface MoreFunctionsView () | |
| 12 | + | |
| 13 | +@property (nonatomic, strong) UISegmentedControl *screenshotSeg; | |
| 14 | +@property (nonatomic, strong) UISegmentedControl *liveSceneSeg; | |
| 15 | +@property (nonatomic, strong) UISegmentedControl *recordSceneSeg; | |
| 16 | +@property (nonatomic, strong) UISegmentedControl *logoSeg; | |
| 17 | + | |
| 18 | +@end | |
| 19 | + | |
| 20 | +@implementation MoreFunctionsView | |
| 21 | + | |
| 22 | +- (instancetype)initWithFrame:(CGRect)frame | |
| 23 | +{ | |
| 24 | + self = [super initWithFrame:frame]; | |
| 25 | + if (self) { | |
| 26 | + | |
| 27 | + [self addSubview:self.screenshotSeg]; | |
| 28 | + [self addSubview:self.liveSceneSeg]; | |
| 29 | + [self addSubview:self.recordSceneSeg]; | |
| 30 | + [self addSubview:self.logoSeg]; | |
| 31 | + [self addSubview:self.bypassRecord]; | |
| 32 | + [self addSubview:self.floatingWindowBtn]; | |
| 33 | + | |
| 34 | + } | |
| 35 | + return self; | |
| 36 | +} | |
| 37 | + | |
| 38 | +#pragma mark - | |
| 39 | +#pragma mark - action | |
| 40 | +- (void)onSegCtrl:(UISegmentedControl *)seg { | |
| 41 | + if (self.moreFuncBlock) { | |
| 42 | + self.moreFuncBlock(seg.tag, seg.selectedSegmentIndex, seg); | |
| 43 | + } | |
| 44 | +} | |
| 45 | + | |
| 46 | +#pragma mark - | |
| 47 | +#pragma mark - getter | |
| 48 | +- (UISegmentedControl *)screenshotSeg | |
| 49 | +{ | |
| 50 | + if (!_screenshotSeg) { | |
| 51 | + NSArray *items = @[ @"截图为文件", | |
| 52 | + @"截图为UIImage"]; | |
| 53 | + | |
| 54 | + _screenshotSeg = [[UISegmentedControl alloc] initWithItems:items]; | |
| 55 | + _screenshotSeg.frame = CGRectMake(95, 0, self.bounds.size.width-105, 30); | |
| 56 | + _screenshotSeg.tintColor= [UIColor blackColor]; | |
| 57 | + _screenshotSeg.layer.cornerRadius = 5; | |
| 58 | + _screenshotSeg.selectedSegmentIndex = -1; | |
| 59 | + _screenshotSeg.tag = MoreFuncTypeScreenshot; | |
| 60 | + [_screenshotSeg addTarget:self action:@selector(onSegCtrl:) forControlEvents:UIControlEventValueChanged]; | |
| 61 | + | |
| 62 | + UILabel *titleLab = [[UILabel alloc] initWithFrame:CGRectMake(-85, 0, 80, 30)]; | |
| 63 | + titleLab.text = @"截图"; | |
| 64 | + titleLab.textColor = [UIColor blackColor]; | |
| 65 | + titleLab.font = [UIFont systemFontOfSize:15]; | |
| 66 | + titleLab.textAlignment = NSTextAlignmentCenter; | |
| 67 | + titleLab.backgroundColor = [UIColor colorWithWhite:0.9 alpha:0.2]; | |
| 68 | + [_screenshotSeg addSubview:titleLab]; | |
| 69 | + } | |
| 70 | + return _screenshotSeg; | |
| 71 | +} | |
| 72 | + | |
| 73 | +- (UISegmentedControl *)liveSceneSeg | |
| 74 | +{ | |
| 75 | + if (!_liveSceneSeg) { | |
| 76 | + NSArray *items = @[ @"默认", | |
| 77 | + @"秀场", | |
| 78 | + @"游戏", | |
| 79 | + ]; | |
| 80 | + | |
| 81 | + _liveSceneSeg = [[UISegmentedControl alloc] initWithItems:items]; | |
| 82 | + _liveSceneSeg.frame = CGRectMake(95, 40, self.bounds.size.width-105, 30); | |
| 83 | + _liveSceneSeg.tintColor= [UIColor blackColor]; | |
| 84 | + _liveSceneSeg.selectedSegmentIndex = 0; | |
| 85 | + _liveSceneSeg.layer.cornerRadius = 5; | |
| 86 | + _liveSceneSeg.selectedSegmentIndex = 1; | |
| 87 | + _liveSceneSeg.tag = MoreFuncTypeLiveScene; | |
| 88 | + [_liveSceneSeg addTarget:self action:@selector(onSegCtrl:) forControlEvents:UIControlEventValueChanged]; | |
| 89 | + | |
| 90 | + UILabel *titleLab = [[UILabel alloc] initWithFrame:CGRectMake(-85, 0, 80, 30)]; | |
| 91 | + titleLab.text = @"直播场景"; | |
| 92 | + titleLab.textColor = [UIColor blackColor]; | |
| 93 | + titleLab.font = [UIFont systemFontOfSize:15]; | |
| 94 | + titleLab.textAlignment = NSTextAlignmentCenter; | |
| 95 | + titleLab.backgroundColor = [UIColor colorWithWhite:0.9 alpha:0.2]; | |
| 96 | + [_liveSceneSeg addSubview:titleLab]; | |
| 97 | + } | |
| 98 | + return _liveSceneSeg; | |
| 99 | +} | |
| 100 | + | |
| 101 | +- (UISegmentedControl *)recordSceneSeg | |
| 102 | +{ | |
| 103 | + if (!_recordSceneSeg) { | |
| 104 | + NSArray *items = @[ @"恒定码率", | |
| 105 | + @"恒定质量", | |
| 106 | + ]; | |
| 107 | + | |
| 108 | + _recordSceneSeg = [[UISegmentedControl alloc] initWithItems:items]; | |
| 109 | + _recordSceneSeg.frame = CGRectMake(95, 80, self.bounds.size.width-105, 30); | |
| 110 | + _recordSceneSeg.tintColor= [UIColor blackColor]; | |
| 111 | + _recordSceneSeg.selectedSegmentIndex = 0; | |
| 112 | + _recordSceneSeg.layer.cornerRadius = 5; | |
| 113 | + _recordSceneSeg.selectedSegmentIndex = 1; | |
| 114 | + _recordSceneSeg.tag = MoreFuncTypeRecordScene; | |
| 115 | + [_recordSceneSeg addTarget:self action:@selector(onSegCtrl:) forControlEvents:UIControlEventValueChanged]; | |
| 116 | + | |
| 117 | + UILabel *titleLab = [[UILabel alloc] initWithFrame:CGRectMake(-85, 0, 80, 30)]; | |
| 118 | + titleLab.text = @"录制场景"; | |
| 119 | + titleLab.textColor = [UIColor blackColor]; | |
| 120 | + titleLab.font = [UIFont systemFontOfSize:15]; | |
| 121 | + titleLab.textAlignment = NSTextAlignmentCenter; | |
| 122 | + titleLab.backgroundColor = [UIColor colorWithWhite:0.9 alpha:0.2]; | |
| 123 | + [_recordSceneSeg addSubview:titleLab]; | |
| 124 | + } | |
| 125 | + return _recordSceneSeg; | |
| 126 | +} | |
| 127 | + | |
| 128 | +- (UISegmentedControl *)logoSeg | |
| 129 | +{ | |
| 130 | + if (!_logoSeg) { | |
| 131 | + NSArray *items = @[ @"清除logo", | |
| 132 | + @"图片logo", | |
| 133 | + @"动态logo", | |
| 134 | + ]; | |
| 135 | + | |
| 136 | + _logoSeg = [[UISegmentedControl alloc] initWithItems:items]; | |
| 137 | + _logoSeg.frame = CGRectMake(95, 120, self.bounds.size.width-105, 30); | |
| 138 | + _logoSeg.tintColor= [UIColor blackColor]; | |
| 139 | + _logoSeg.selectedSegmentIndex = 0; | |
| 140 | + _logoSeg.layer.cornerRadius = 5; | |
| 141 | + _logoSeg.selectedSegmentIndex = 1; | |
| 142 | + _logoSeg.tag = MoreFuncTypeLogo; | |
| 143 | + [_logoSeg addTarget:self action:@selector(onSegCtrl:) forControlEvents:UIControlEventValueChanged]; | |
| 144 | + | |
| 145 | + UILabel *titleLab = [[UILabel alloc] initWithFrame:CGRectMake(-85, 0, 80, 30)]; | |
| 146 | + titleLab.text = @"Logo设置"; | |
| 147 | + titleLab.textColor = [UIColor blackColor]; | |
| 148 | + titleLab.font = [UIFont systemFontOfSize:15]; | |
| 149 | + titleLab.textAlignment = NSTextAlignmentCenter; | |
| 150 | + titleLab.backgroundColor = [UIColor colorWithWhite:0.9 alpha:0.2]; | |
| 151 | + [_logoSeg addSubview:titleLab]; | |
| 152 | + } | |
| 153 | + return _logoSeg; | |
| 154 | +} | |
| 155 | + | |
| 156 | +- (UISwitch *)bypassRecord | |
| 157 | +{ | |
| 158 | + if (!_bypassRecord) { | |
| 159 | + _bypassRecord = [[UISwitch alloc] initWithFrame:CGRectMake(95, 160, 100, 30)]; | |
| 160 | + | |
| 161 | + UILabel *titleLab = [[UILabel alloc] initWithFrame:CGRectMake(-85, 0, 80, 30)]; | |
| 162 | + titleLab.textColor = [UIColor blackColor]; | |
| 163 | + titleLab.text = @"旁路录制"; | |
| 164 | + titleLab.font = [UIFont systemFontOfSize:15]; | |
| 165 | + titleLab.textAlignment = NSTextAlignmentCenter; | |
| 166 | + titleLab.backgroundColor = [UIColor colorWithWhite:0.9 alpha:0.2]; | |
| 167 | + [_bypassRecord addSubview:titleLab]; | |
| 168 | + } | |
| 169 | + return _bypassRecord; | |
| 170 | +} | |
| 171 | + | |
| 172 | +- (UIButton *)floatingWindowBtn | |
| 173 | +{ | |
| 174 | + if (!_floatingWindowBtn) { | |
| 175 | + _floatingWindowBtn = [UIButton buttonWithType:UIButtonTypeCustom]; | |
| 176 | + _floatingWindowBtn.frame = CGRectMake(220, 160, 80, 30); | |
| 177 | + [_floatingWindowBtn setTitle:@"悬浮窗" forState: UIControlStateNormal]; | |
| 178 | + _floatingWindowBtn.titleLabel.font = [UIFont systemFontOfSize:15]; | |
| 179 | + [_floatingWindowBtn setTitleColor:[UIColor colorWithRed:23/255.0 green:110/255.0 blue:254/255.0 alpha:1] forState:UIControlStateNormal]; | |
| 180 | + _floatingWindowBtn.layer.cornerRadius = 3; | |
| 181 | + _floatingWindowBtn.layer.masksToBounds = YES; | |
| 182 | + _floatingWindowBtn.layer.borderColor = [UIColor blackColor].CGColor; | |
| 183 | + _floatingWindowBtn.layer.borderWidth = 1; | |
| 184 | + | |
| 185 | + } | |
| 186 | + return _floatingWindowBtn; | |
| 187 | +} | |
| 188 | + | |
| 189 | +/* | |
| 190 | +// Only override drawRect: if you perform custom drawing. | |
| 191 | +// An empty implementation adversely affects performance during animation. | |
| 192 | +- (void)drawRect:(CGRect)rect { | |
| 193 | + // Drawing code | |
| 194 | +} | |
| 195 | +*/ | |
| 196 | + | |
| 197 | +@end | ... | ... |
Example/CNLivePlayer/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 | ... | ... |
Example/CNLivePlayer/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 blackColor]; | |
| 53 | + _nameL.backgroundColor = [UIColor colorWithRed:192/255.0 green:192/255.0 blue:192/255.0 alpha:1]; | |
| 54 | + _nameL.font = [UIFont systemFontOfSize:15]; | |
| 55 | + _nameL.layer.cornerRadius = 5; | |
| 56 | + _nameL.layer.masksToBounds = YES; | |
| 57 | + } | |
| 58 | + return _nameL; | |
| 59 | +} | |
| 60 | + | |
| 61 | +- (UILabel *)valueL | |
| 62 | +{ | |
| 63 | + if (!_valueL) { | |
| 64 | + _valueL = [[UILabel alloc] initWithFrame:CGRectMake(self.bounds.size.width-40, 0, 40, 24)]; | |
| 65 | + _valueL.text = @"50"; | |
| 66 | + _valueL.textAlignment = NSTextAlignmentCenter; | |
| 67 | + _valueL.textColor = [UIColor blackColor]; | |
| 68 | + _valueL.backgroundColor = [UIColor colorWithRed:192/255.0 green:192/255.0 blue:192/255.0 alpha:1]; | |
| 69 | + _valueL.font = [UIFont systemFontOfSize:15]; | |
| 70 | + _valueL.layer.cornerRadius = 5; | |
| 71 | + _valueL.layer.masksToBounds = YES; | |
| 72 | + | |
| 73 | + } | |
| 74 | + return _valueL; | |
| 75 | +} | |
| 76 | + | |
| 77 | +- (UISlider *)slider | |
| 78 | +{ | |
| 79 | + if (!_slider) { | |
| 80 | + _slider = [[UISlider alloc] initWithFrame:CGRectMake(40, 0, self.bounds.size.width-80, 24)]; | |
| 81 | + [_slider setThumbImage:[UIImage imageNamed:@"btn_dot"] forState:UIControlStateNormal]; | |
| 82 | + [_slider setMinimumTrackTintColor:[UIColor redColor]]; | |
| 83 | + [_slider setMaximumTrackTintColor:[UIColor whiteColor]]; | |
| 84 | + _slider.value = 0.5; | |
| 85 | + | |
| 86 | + [_slider addTarget:self action:@selector(onSlider:) forControlEvents:UIControlEventValueChanged]; | |
| 87 | + } | |
| 88 | + return _slider; | |
| 89 | +} | |
| 90 | +@end | ... | ... |
Example/CNLivePlayer/Streamer/StreamerDetailViewController.h
0 → 100644
| 1 | +// | |
| 2 | +// LiveViewController.h | |
| 3 | +// CNLiveLiveDemo | |
| 4 | +// | |
| 5 | +// Created by Android on 16/8/10. | |
| 6 | +// Copyright © 2016年 Android. All rights reserved. | |
| 7 | +// | |
| 8 | + | |
| 9 | +#import <UIKit/UIKit.h> | |
| 10 | + | |
| 11 | +@interface StreamerDetailViewController : UIViewController | |
| 12 | + | |
| 13 | +@property (nonatomic, assign) BOOL isAuthLive; | |
| 14 | +@property (nonatomic, assign) BOOL isRecord; | |
| 15 | + | |
| 16 | +@property (nonatomic, strong) NSURL *url; | |
| 17 | + | |
| 18 | +@end | ... | ... |
Example/CNLivePlayer/Streamer/StreamerDetailViewController.m
0 → 100644
| 1 | +// | |
| 2 | +// LiveViewController.m | |
| 3 | +// CNLiveLiveDemo | |
| 4 | +// | |
| 5 | +// Created by Android on 16/8/10. | |
| 6 | +// Copyright © 2016年 Android. All rights reserved. | |
| 7 | +// | |
| 8 | + | |
| 9 | +#import "StreamerDetailViewController.h" | |
| 10 | +#import "FilterFunctionView.h" | |
| 11 | +#import "CNLivePlayerManager.h" | |
| 12 | +#import "AudioCfgView.h" | |
| 13 | +#import "LoadingView.h" | |
| 14 | +#import "MoreFunctionsView.h" | |
| 15 | +#import <GPUImage/GPUImage.h> | |
| 16 | +#import <YYImage/YYImage.h> | |
| 17 | +#import "FloatingViewController.h" | |
| 18 | +#import "CNLiveStreamerKit.h" | |
| 19 | + | |
| 20 | +#import "CNLiveAudioCapture.h" | |
| 21 | +#import "CNLiveBeautifyFaceFilter.h" | |
| 22 | +#import "CNLiveStreamerBase.h" | |
| 23 | +#import "CNLiveWatermark.h" | |
| 24 | + | |
| 25 | +#define Width [UIScreen mainScreen].bounds.size.width | |
| 26 | +#define Height [UIScreen mainScreen].bounds.size.height | |
| 27 | + | |
| 28 | +#define SYSTEM_VERSION_GE_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending) | |
| 29 | + | |
| 30 | +@interface StreamerDetailViewController ()<UIGestureRecognizerDelegate,LoadingViewDelegate> | |
| 31 | +{ | |
| 32 | + UIButton *_startLiveBtn; | |
| 33 | + UIButton *_flashBtn; | |
| 34 | + UIButton *_previewBtn; | |
| 35 | + CGFloat _currentPinchZoomFactor;//当前触摸缩放因子 | |
| 36 | + | |
| 37 | + NSString *_bypassRecFile; // 旁路录制 | |
| 38 | + | |
| 39 | + YYImageDecoder * _animateDecoder; | |
| 40 | + int _animateIdx; | |
| 41 | + | |
| 42 | + NSTimeInterval _dlTime; | |
| 43 | + | |
| 44 | +} | |
| 45 | + | |
| 46 | +@property (nonatomic,strong) UIView *captureView; | |
| 47 | +@property (nonatomic,strong) UILabel *stateLab; | |
| 48 | +@property (nonatomic,strong) NSURL *hostURL; | |
| 49 | +@property (nonatomic,strong) FilterFunctionView *filterView; | |
| 50 | +@property (nonatomic,strong) CNLiveStreamerKit *kitCN; //直播推流 | |
| 51 | +@property (nonatomic,strong) AudioCfgView *audioCfgView; //声音相关设置 | |
| 52 | +@property (nonatomic, strong) LoadingView *loadingView; | |
| 53 | +@property (nonatomic, strong) MoreFunctionsView *moreFuncsView; | |
| 54 | + | |
| 55 | +@property (nonatomic, strong) NSLock *dlLock; | |
| 56 | +@property (nonatomic, strong) GPUImagePicture *logoPicure; | |
| 57 | +@property (nonatomic, strong) CADisplayLink *displayLink; | |
| 58 | + | |
| 59 | +@end | |
| 60 | + | |
| 61 | +@implementation StreamerDetailViewController | |
| 62 | + | |
| 63 | +// 旋转处理,通过旋转bgView来做到画面相对手机静止不动 | |
| 64 | +- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator NS_AVAILABLE_IOS(8_0) | |
| 65 | +{ | |
| 66 | + [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; | |
| 67 | + | |
| 68 | + // size | |
| 69 | + CGSize screenSize = [UIScreen mainScreen].bounds.size; | |
| 70 | + CGFloat minLength = MIN(screenSize.width, screenSize.height); | |
| 71 | + CGFloat maxLength = MAX(screenSize.width, screenSize.height); | |
| 72 | + CGRect newFrame; | |
| 73 | + | |
| 74 | + // frame | |
| 75 | + CGAffineTransform newTransform; | |
| 76 | + // need stay frame after animation | |
| 77 | + CGAffineTransform newTransformOfStay; | |
| 78 | + // whether need to stay | |
| 79 | + __block BOOL needStay = NO; | |
| 80 | + | |
| 81 | + UIInterfaceOrientation currentInterfaceOrientation = [UIApplication sharedApplication].statusBarOrientation; | |
| 82 | + UIDeviceOrientation toDeviceOrientation = [UIDevice currentDevice].orientation; | |
| 83 | + | |
| 84 | + if (toDeviceOrientation == UIDeviceOrientationPortrait) { | |
| 85 | + newTransform = CGAffineTransformIdentity; | |
| 86 | + newFrame = CGRectMake(0, 0, minLength, maxLength); | |
| 87 | + } else { | |
| 88 | + if (currentInterfaceOrientation == UIInterfaceOrientationPortrait) { | |
| 89 | + newTransform = CGAffineTransformMakeRotation(M_PI_2*(toDeviceOrientation == UIDeviceOrientationLandscapeRight ? 1 : -1)); | |
| 90 | + } else { | |
| 91 | + needStay = YES; | |
| 92 | + if (currentInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) { | |
| 93 | + newTransform = CGAffineTransformRotate(_captureView.transform, M_PI * 1.00001); | |
| 94 | + newTransformOfStay = CGAffineTransformRotate(_captureView.transform, M_PI); | |
| 95 | + }else{ | |
| 96 | + newTransform = CGAffineTransformRotate(_captureView.transform, SYSTEM_VERSION_GE_TO(@"8.0") ? 1.00001 * M_PI : M_PI * 0.99999); | |
| 97 | + newTransformOfStay = CGAffineTransformRotate(_captureView.transform, M_PI); | |
| 98 | + } | |
| 99 | + } | |
| 100 | + newFrame = CGRectMake(0, 0, maxLength, minLength); | |
| 101 | + } | |
| 102 | + | |
| 103 | + __weak typeof(self) weakSelf = self; | |
| 104 | + [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) { | |
| 105 | + | |
| 106 | + if(SYSTEM_VERSION_GE_TO(@"8.0")) { | |
| 107 | + [self onViewRotate]; | |
| 108 | + } | |
| 109 | + | |
| 110 | + __strong __typeof(weakSelf) strongSelf = weakSelf; | |
| 111 | + if (!strongSelf) { | |
| 112 | + return ; | |
| 113 | + } | |
| 114 | + _captureView.transform = newTransform; | |
| 115 | + _captureView.frame = newFrame; | |
| 116 | + } completion:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) { | |
| 117 | + __strong __typeof(weakSelf)strongSelf = weakSelf; | |
| 118 | + if (!strongSelf) { | |
| 119 | + return ; | |
| 120 | + } | |
| 121 | + if (needStay) { | |
| 122 | + _captureView.transform = newTransformOfStay; | |
| 123 | + _captureView.frame = newFrame; | |
| 124 | + needStay = NO; | |
| 125 | + } | |
| 126 | + | |
| 127 | + _previewBtn.frame = CGRectMake(5, Height-40, 90, 30); | |
| 128 | + _startLiveBtn.frame = CGRectMake(Width-95, Height-40, 90, 30); | |
| 129 | + _stateLab.frame = CGRectMake(0, Height/2-50, Width, 100); | |
| 130 | + | |
| 131 | + }]; | |
| 132 | +} | |
| 133 | + | |
| 134 | +- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation{ | |
| 135 | + if(SYSTEM_VERSION_GE_TO(@"8.0")) { | |
| 136 | + return; | |
| 137 | + } | |
| 138 | + [self onViewRotate]; | |
| 139 | +} | |
| 140 | + | |
| 141 | +- (void)viewDidLoad { | |
| 142 | + [super viewDidLoad]; | |
| 143 | + | |
| 144 | + self.view.backgroundColor = [UIColor whiteColor]; | |
| 145 | + | |
| 146 | + [self.view addSubview:self.captureView]; | |
| 147 | + [self.view addSubview:self.filterView]; | |
| 148 | + [self.view addSubview:self.stateLab]; | |
| 149 | + [self.view addSubview:self.audioCfgView]; | |
| 150 | + [self.captureView addSubview:self.loadingView]; | |
| 151 | + [self.view addSubview:self.moreFuncsView]; | |
| 152 | + [self createUI]; | |
| 153 | + | |
| 154 | + _bypassRecFile =[NSHomeDirectory() stringByAppendingString:@"/Library/Caches/rec.mp4"]; | |
| 155 | + | |
| 156 | + if (_isAuthLive) { | |
| 157 | + | |
| 158 | + NSDate *date = [NSDate date]; | |
| 159 | + NSInteger time = [date timeIntervalSince1970]; | |
| 160 | + NSString *activityId = [NSString stringWithFormat:@"%ld", (long)time]; | |
| 161 | + | |
| 162 | + _kitCN = [[CNLiveStreamerKit alloc] initVodStreamerWithDefaultConfig]; | |
| 163 | + _kitCN.activityId = activityId; | |
| 164 | + _kitCN.channelId = @"498122"; | |
| 165 | +// _kitCN.isHorizontalScreen = YES; | |
| 166 | + | |
| 167 | + //设置重连参数 | |
| 168 | + _kitCN.maxAutoRetry = 3; | |
| 169 | + _kitCN.autoRetryDelay = 5; | |
| 170 | + | |
| 171 | + [self setStreamerCfg]; | |
| 172 | + [self addObservers]; | |
| 173 | + | |
| 174 | + //声音相关设置 | |
| 175 | + [self audioCfg]; | |
| 176 | + [self moreFunctionCfg]; | |
| 177 | + | |
| 178 | + | |
| 179 | + }else{ | |
| 180 | + | |
| 181 | + _kitCN = [[CNLiveStreamerKit alloc] initWithDefaultConfig:NO]; | |
| 182 | + _hostURL = _url; | |
| 183 | + | |
| 184 | + [self setStreamerCfg]; | |
| 185 | + [self addObservers]; | |
| 186 | + [self audioCfg]; | |
| 187 | + [self moreFunctionCfg]; | |
| 188 | + } | |
| 189 | + | |
| 190 | + __weak StreamerDetailViewController *weakself = self; | |
| 191 | + _kitCN.streamerBase.bypassRecordStateChange = ^(CNLiveRecordState state) { | |
| 192 | + //旁路录制状态改变会调用该block | |
| 193 | + [weakself onBypassRecordStateChange:state]; | |
| 194 | + }; | |
| 195 | + | |
| 196 | +} | |
| 197 | + | |
| 198 | +- (void)createUI { | |
| 199 | + _startLiveBtn = [self addTextButton:@"开始推流" selectedTitle:@"停止推流" frame:CGRectMake(Width-95, Height-40, 90, 30) radius:7 action:@selector(startStreaming:)]; | |
| 200 | + _previewBtn = [self addTextButton:@"关闭预览" selectedTitle:@"开启预览" frame:CGRectMake(5, Height-40, 90, 30) radius:7 action:@selector(startPreview:)]; | |
| 201 | + | |
| 202 | + [self addImageBtn:[UIImage imageNamed:@"back"] selectedImg:nil frame:CGRectMake(20, 20, 33, 33) action:@selector(quit)]; | |
| 203 | + [self addImageBtn:[UIImage imageNamed:@"camera"] selectedImg:nil frame:CGRectMake(70, 20, 33, 33) action:@selector(changeCamera:)]; | |
| 204 | + _flashBtn = [self addImageBtn:[UIImage imageNamed:@"flash close"] selectedImg:[UIImage imageNamed:@"flash open"] frame:CGRectMake(120, 20, 33, 33) action:@selector(flash:)]; | |
| 205 | + [self addImageBtn:[UIImage imageNamed:@"filter"] selectedImg:[UIImage imageNamed:@"filter"] frame:CGRectMake(170, 20, 33, 33) action:@selector(openFilter:)]; | |
| 206 | + [self addImageBtn:[UIImage imageNamed:@"voice"] selectedImg:[UIImage imageNamed:@"voice"] frame:CGRectMake(220, 20, 33, 33) action:@selector(voiceCfg:)]; | |
| 207 | + [self addImageBtn:[UIImage imageNamed:@"更多"] selectedImg:[UIImage imageNamed:@"更多"] frame:CGRectMake(Width-53, 20, 33, 33) action:@selector(moreFunction:)]; | |
| 208 | + | |
| 209 | + UITapGestureRecognizer * singleRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onTap:)]; | |
| 210 | + singleRecognizer.delegate = self; | |
| 211 | + [self.captureView addGestureRecognizer:singleRecognizer]; | |
| 212 | + | |
| 213 | + UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(pinchDetected:)]; | |
| 214 | + [self.view addGestureRecognizer:pinch]; | |
| 215 | + | |
| 216 | +} | |
| 217 | + | |
| 218 | +#pragma mark - initialization | |
| 219 | +- (void)setStreamerCfg | |
| 220 | +{ | |
| 221 | + //采集配置 | |
| 222 | + _kitCN.capPreset = AVCaptureSessionPreset1280x720; | |
| 223 | + _kitCN.previewDimension = CGSizeMake(720, 1280); | |
| 224 | + _kitCN.streamDimension = CGSizeMake(720, 1280); | |
| 225 | + _kitCN.videoFPS = 15; | |
| 226 | + _kitCN.cameraPosition = AVCaptureDevicePositionFront; | |
| 227 | + | |
| 228 | + //推流配置 | |
| 229 | + _kitCN.streamerBase.videoCodec = CNLiveVideoCodec_AUTO; | |
| 230 | + _kitCN.streamerBase.videoInitBitrate = 900; | |
| 231 | + _kitCN.streamerBase.videoMaxBitrate = 900; | |
| 232 | + _kitCN.streamerBase.videoMinBitrate = 300; | |
| 233 | + _kitCN.streamerBase.maxKeyInterval = 2; | |
| 234 | + _kitCN.streamerBase.audiokBPS = 48; | |
| 235 | + | |
| 236 | + //设置画面朝向 | |
| 237 | + [_kitCN setVideoOrientationBy:[[UIApplication sharedApplication] statusBarOrientation]]; | |
| 238 | + [_kitCN startPreview:self.captureView]; | |
| 239 | + | |
| 240 | + //水印图片 | |
| 241 | + _kitCN.watermark.logoPic = [[GPUImagePicture alloc] initWithImage:[UIImage imageNamed:@"互动电视180x180"]]; | |
| 242 | +; | |
| 243 | + _kitCN.watermark.logoRect = CGRectMake(0.05, 0.05, 60, 60); | |
| 244 | + _kitCN.watermark.logoAlpha = 0.6; | |
| 245 | + | |
| 246 | + //水印文字 | |
| 247 | + _kitCN.watermark.textLabel = [[UILabel alloc] init]; | |
| 248 | + _kitCN.watermark.textLabel.text = [NSString stringWithFormat:@"cnlive"]; | |
| 249 | + _kitCN.watermark.textLabel.font = [UIFont systemFontOfSize:8]; | |
| 250 | + _kitCN.watermark.textRect = CGRectMake(0.05, 0.1, 0.09, 0.04); | |
| 251 | + [_kitCN.watermark updateTextLabel]; | |
| 252 | + | |
| 253 | +} | |
| 254 | + | |
| 255 | +#pragma mark - | |
| 256 | +#pragma mark - 旋转 | |
| 257 | +- (void)onViewRotate { | |
| 258 | + UIInterfaceOrientation orie = [[UIApplication sharedApplication] statusBarOrientation]; | |
| 259 | + [_kitCN rotateStreamTo:orie]; | |
| 260 | + | |
| 261 | +} | |
| 262 | + | |
| 263 | +#pragma mark - Action | |
| 264 | + | |
| 265 | +- (void)startPreview:(UIButton *)button | |
| 266 | +{ | |
| 267 | + button.selected = !button.selected; | |
| 268 | + if (button.selected) { | |
| 269 | + _startLiveBtn.enabled = NO; | |
| 270 | + if (_kitCN.streamState == CNLiveStreamStateConnected) { | |
| 271 | + [_kitCN stopStream]; | |
| 272 | + _startLiveBtn.selected = NO; | |
| 273 | + } | |
| 274 | + [_kitCN stopPreview]; | |
| 275 | + }else{ | |
| 276 | + [_kitCN startPreview:self.captureView]; | |
| 277 | + _startLiveBtn.enabled = YES; | |
| 278 | + } | |
| 279 | +} | |
| 280 | + | |
| 281 | +- (void)startStreaming:(UIButton *)button | |
| 282 | +{ | |
| 283 | + button.selected = !button.selected; | |
| 284 | + | |
| 285 | + if (button.selected) { | |
| 286 | + | |
| 287 | + if (!_isRecord) { //若不是本地录制 | |
| 288 | + | |
| 289 | + if (_isAuthLive) { | |
| 290 | + | |
| 291 | + [_loadingView setLoadingViewStyle:LoadingViewStyleStartLoading]; | |
| 292 | + | |
| 293 | + //SDK内部创建活动并开启推流 | |
| 294 | + [_kitCN startStream:^{ | |
| 295 | + [_loadingView setLoadingViewStyle:LoadingViewStyleStopLoading]; | |
| 296 | + NSLog(@"开启推流成功 ------- success"); | |
| 297 | + } failure:^(NSDictionary *errorDic) { | |
| 298 | + [_loadingView setLoadingViewStyle:LoadingViewStyleStopLoading]; | |
| 299 | + [self toast:errorDic[@"errorMessage"]]; | |
| 300 | + _startLiveBtn.selected = NO; | |
| 301 | + }]; | |
| 302 | + | |
| 303 | + //由后台创建活动,SDK只负责开启活动 | |
| 304 | +// [_kitCN startStreamWithUrl:@"rtmp://jsrtmp.up.cnlive.com/live/60_iostest?vdoid=60_1496281944" activityId:@"60_1496281944" success:^{ | |
| 305 | +// [_loadingView setLoadingViewStyle:LoadingViewStyleStopLoading]; | |
| 306 | +// NSLog(@"开启推流成功 ------- success"); | |
| 307 | +// } failure:^(NSDictionary *errorDic) { | |
| 308 | +// [_loadingView setLoadingViewStyle:LoadingViewStyleStopLoading]; | |
| 309 | +// [self toast:errorDic[@"errorMessage"]]; | |
| 310 | +// _startLiveBtn.selected = NO; | |
| 311 | +// }]; | |
| 312 | + | |
| 313 | + }else{ | |
| 314 | + [_kitCN startStream:_hostURL]; | |
| 315 | + } | |
| 316 | + | |
| 317 | + } else { | |
| 318 | + | |
| 319 | + NSDate *date = [NSDate date]; | |
| 320 | + NSInteger time = [date timeIntervalSince1970]; | |
| 321 | + NSString *videoName = [NSString stringWithFormat:@"%ld", (long)time]; | |
| 322 | + | |
| 323 | + //存储地址 | |
| 324 | + NSString *path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.mp4", videoName]]; | |
| 325 | + _hostURL = [NSURL URLWithString:path]; | |
| 326 | + [_kitCN startStream:_hostURL]; | |
| 327 | + } | |
| 328 | + | |
| 329 | + }else{ | |
| 330 | + | |
| 331 | + if (!_isRecord) { | |
| 332 | + [_kitCN stopStream]; | |
| 333 | + } else { | |
| 334 | + [_kitCN stopRecord]; | |
| 335 | + | |
| 336 | + [self saveVideoToAlbum:[_hostURL absoluteString]]; | |
| 337 | + } | |
| 338 | + _stateLab.text = nil; | |
| 339 | + } | |
| 340 | +} | |
| 341 | + | |
| 342 | +- (void)openFilter:(UIButton *)button { | |
| 343 | + _audioCfgView.hidden = YES; | |
| 344 | + _moreFuncsView.hidden = YES; | |
| 345 | + _filterView.hidden = !_filterView.hidden; | |
| 346 | + | |
| 347 | + if (_filterView.hidden == NO) { | |
| 348 | + | |
| 349 | + __weak StreamerDetailViewController *weakself = self; | |
| 350 | + | |
| 351 | + _filterView.filterViewBlock = ^(float grindRatio , float whitenRatio, float intensity){ | |
| 352 | + | |
| 353 | + //设置美颜参数 | |
| 354 | + [weakself.kitCN.beautifyFaceFilter filterAdjustingParameterWithGrindRatio:grindRatio | |
| 355 | + whitenRatio:whitenRatio | |
| 356 | + intensity:intensity]; | |
| 357 | + }; | |
| 358 | + | |
| 359 | + //设置美颜类型 | |
| 360 | + _filterView.currentTypeBlock = ^(NSInteger currentType){ | |
| 361 | + [weakself.kitCN.beautifyFaceFilter setBeautyType:currentType]; | |
| 362 | + }; | |
| 363 | + | |
| 364 | + //设置特效美颜类型 | |
| 365 | + _filterView.currentIdxBlock = ^(NSInteger currentIdx){ | |
| 366 | + [weakself.kitCN.beautifyFaceFilter setCurEffectIdx:currentIdx]; | |
| 367 | + }; | |
| 368 | + | |
| 369 | + } | |
| 370 | +} | |
| 371 | + | |
| 372 | +- (void)changeCamera:(UIButton *)button { | |
| 373 | + [_kitCN switchCamera]; | |
| 374 | + if (![_kitCN isTorchSupported]) { | |
| 375 | + _flashBtn.selected = NO; | |
| 376 | + } | |
| 377 | +} | |
| 378 | + | |
| 379 | +- (void)flash:(UIButton *)button { | |
| 380 | + if ([_kitCN isTorchSupported]) { | |
| 381 | + [_kitCN toggleTorch]; | |
| 382 | + button.selected = !button.selected; | |
| 383 | + } | |
| 384 | +} | |
| 385 | + | |
| 386 | +- (void)quit { | |
| 387 | + if (_kitCN.streamState == CNLiveStreamStateConnected) { | |
| 388 | + [_kitCN stopStream]; | |
| 389 | + } | |
| 390 | + if (_kitCN.captureState == CNLiveCaptureStateCapturing) { | |
| 391 | + [_kitCN stopPreview]; | |
| 392 | + } | |
| 393 | + | |
| 394 | + [_kitCN quitStreaming]; | |
| 395 | + _loadingView.delegate = self; | |
| 396 | + [[NSNotificationCenter defaultCenter] removeObserver:self]; | |
| 397 | + | |
| 398 | + [self dismissViewControllerAnimated:YES completion:NULL]; | |
| 399 | + | |
| 400 | +} | |
| 401 | + | |
| 402 | +//旁路录制 | |
| 403 | +- (void)bypassRecordOn:(UISwitch *)sender { | |
| 404 | + | |
| 405 | + BOOL bRec = _kitCN.streamerBase.bypassRecordState == CNLiveRecordStateRecording; | |
| 406 | + if (_moreFuncsView.bypassRecord.on){ | |
| 407 | + if ( _kitCN.streamerBase.isStreaming && !bRec){ | |
| 408 | + // 如果启动录像时使用和上次相同的路径,则会覆盖掉上一次录像的文件内容 | |
| 409 | + [self deleteFile:_bypassRecFile]; | |
| 410 | + NSURL *url =[[NSURL alloc] initFileURLWithPath:_bypassRecFile]; | |
| 411 | + [_kitCN.streamerBase startBypassRecord:url]; | |
| 412 | + | |
| 413 | + } | |
| 414 | + else { | |
| 415 | + NSString * msg = @"推流过程中才能旁路录像"; | |
| 416 | + [self toast:msg]; | |
| 417 | + _moreFuncsView.bypassRecord.on = NO; | |
| 418 | + } | |
| 419 | + } | |
| 420 | + else if (bRec){ | |
| 421 | + [_kitCN.streamerBase stopBypassRecord]; | |
| 422 | + } | |
| 423 | + | |
| 424 | +} | |
| 425 | + | |
| 426 | +- (void)floatingWindowBtnAction { | |
| 427 | + FloatingViewController *vc = [[FloatingViewController alloc] init]; | |
| 428 | + vc.kit = _kitCN; | |
| 429 | + [self presentViewController:vc animated:YES completion:NULL]; | |
| 430 | +} | |
| 431 | + | |
| 432 | + | |
| 433 | +//对焦与曝光 | |
| 434 | +- (void)onTap:(UIGestureRecognizer *)sender | |
| 435 | +{ | |
| 436 | + CGPoint current = [sender locationInView:self.view]; | |
| 437 | + CGPoint point = [self convertToPointOfInterestFromViewCoordinates:current]; | |
| 438 | + [_kitCN exposureAtPoint:point]; | |
| 439 | + [_kitCN focusAtPoint:point]; | |
| 440 | +} | |
| 441 | + | |
| 442 | +//缩放 | |
| 443 | +- (void)pinchDetected:(UIPinchGestureRecognizer *)recognizer{ | |
| 444 | + if (recognizer.state == UIGestureRecognizerStateBegan) { | |
| 445 | + _currentPinchZoomFactor = _kitCN.pinchZoomFactor; | |
| 446 | + } | |
| 447 | + CGFloat zoomFactor = _currentPinchZoomFactor * recognizer.scale;//当前触摸缩放因子*坐标比例 | |
| 448 | + [_kitCN setPinchZoomFactor:zoomFactor]; | |
| 449 | +} | |
| 450 | + | |
| 451 | +- (void)voiceCfg:(UIButton *)button { | |
| 452 | + _filterView.hidden = YES; | |
| 453 | + _moreFuncsView.hidden = YES; | |
| 454 | + _audioCfgView.hidden = !_audioCfgView.hidden; | |
| 455 | +} | |
| 456 | + | |
| 457 | +- (void)moreFunction:(UIButton *)button { | |
| 458 | + _filterView.hidden = YES; | |
| 459 | + _audioCfgView.hidden = YES; | |
| 460 | + _moreFuncsView.hidden = !_moreFuncsView.hidden; | |
| 461 | +} | |
| 462 | + | |
| 463 | +- (void)audioCfg { | |
| 464 | + //声音相关设置 | |
| 465 | + __weak StreamerDetailViewController *weakself = self; | |
| 466 | + | |
| 467 | + _audioCfgView.audioEffectBlock = ^(int type) { //音效 | |
| 468 | + weakself.kitCN.audioCapture.audioEffectType = type; | |
| 469 | + }; | |
| 470 | + | |
| 471 | + _audioCfgView.reverbTypeBlock = ^(int type) { //混响 | |
| 472 | + weakself.kitCN.audioCapture.reverbType = type; | |
| 473 | + }; | |
| 474 | + | |
| 475 | + _audioCfgView.bPlayCapturedAudio = ^(BOOL isOn) { //耳返 | |
| 476 | + if ([CNLiveAudioCapture isHeadsetPluggedIn]) { | |
| 477 | + [weakself.kitCN.audioCapture setBPlayCapturedAudio:isOn]; | |
| 478 | + } else { | |
| 479 | + weakself.audioCfgView.bPlaySwitch.on = NO; | |
| 480 | + [weakself toast:@"未检测到耳机"]; | |
| 481 | + } | |
| 482 | + }; | |
| 483 | + | |
| 484 | + _audioCfgView.micVolumeBlock = ^(float micVolume) { //麦克风音量 | |
| 485 | + weakself.kitCN.audioCapture.micVolume = micVolume; | |
| 486 | + }; | |
| 487 | + | |
| 488 | + _audioCfgView.bPlayVolumeBlock = ^(float bPlayVolume) { //耳返音量 | |
| 489 | + weakself.kitCN.audioCapture.bPlayVolume = bPlayVolume; | |
| 490 | + }; | |
| 491 | + | |
| 492 | +} | |
| 493 | + | |
| 494 | +- (void)moreFunctionCfg { | |
| 495 | + | |
| 496 | + __weak StreamerDetailViewController *weakself = self; | |
| 497 | + | |
| 498 | + _moreFuncsView.moreFuncBlock = ^(MoreFuncType type, NSInteger idx, UISegmentedControl *seg) { | |
| 499 | + | |
| 500 | + NSLog(@"type:%lu--idx:%ld", (unsigned long)type,(long)idx); | |
| 501 | + | |
| 502 | + if (type == MoreFuncTypeScreenshot) { //截图 | |
| 503 | + | |
| 504 | + seg.selectedSegmentIndex = -1; | |
| 505 | + | |
| 506 | + switch (idx) { | |
| 507 | + case 0: { | |
| 508 | + NSString *path = @"snapshot/c.jpg"; | |
| 509 | + [weakself.kitCN.streamerBase takePhotoWithQuality:1 fileName:path]; | |
| 510 | + NSLog(@"Snapshot save to %@", path); | |
| 511 | + } | |
| 512 | + break; | |
| 513 | + case 1: { | |
| 514 | + [weakself.kitCN.streamerBase getSnapshotWithCompletion:^(UIImage * img){ | |
| 515 | + //所截图片 | |
| 516 | + }]; | |
| 517 | + } | |
| 518 | + break; | |
| 519 | + | |
| 520 | + default: | |
| 521 | + break; | |
| 522 | + } | |
| 523 | + | |
| 524 | + } else if (type == MoreFuncTypeLiveScene) { //直播场景 | |
| 525 | + | |
| 526 | + weakself.kitCN.streamerBase.liveScene = (CNLiveLiveScene)idx; | |
| 527 | + | |
| 528 | + } else if (type == MoreFuncTypeRecordScene) { //录制场景 | |
| 529 | + | |
| 530 | + weakself.kitCN.streamerBase.recScene = (CNLiveRecScene)idx; | |
| 531 | + | |
| 532 | + } else { //logo | |
| 533 | + | |
| 534 | + switch (idx) { | |
| 535 | + case 0: { | |
| 536 | + [weakself.dlLock lock]; | |
| 537 | + _animateDecoder = nil; | |
| 538 | + weakself.kitCN.watermark.logoPic = nil; | |
| 539 | + [weakself.dlLock unlock]; | |
| 540 | + } | |
| 541 | + break; | |
| 542 | + case 1: { | |
| 543 | + [weakself.dlLock lock]; | |
| 544 | + _animateDecoder = nil; | |
| 545 | + weakself.kitCN.watermark.logoPic = [[GPUImagePicture alloc] initWithImage:[UIImage imageNamed:@"互动电视180x180"]]; | |
| 546 | + [weakself.dlLock unlock]; | |
| 547 | + } | |
| 548 | + break; | |
| 549 | + case 2: { | |
| 550 | + | |
| 551 | + [weakself setupAnimateLogo:[[NSBundle mainBundle] pathForResource:@"house" ofType:@"gif"]]; | |
| 552 | + } | |
| 553 | + break; | |
| 554 | + | |
| 555 | + default: | |
| 556 | + break; | |
| 557 | + } | |
| 558 | + } | |
| 559 | + | |
| 560 | + }; | |
| 561 | + | |
| 562 | + | |
| 563 | +} | |
| 564 | + | |
| 565 | +- (void)setupAnimateLogo:(NSString *)path { | |
| 566 | + NSData *data = [NSData dataWithContentsOfFile:path]; | |
| 567 | + [_dlLock lock]; | |
| 568 | + _animateDecoder = [YYImageDecoder decoderWithData:data scale:[[UIScreen mainScreen] scale]]; | |
| 569 | + [_kitCN.watermark setLogoOrientaion:UIImageOrientationUp]; | |
| 570 | + [_dlLock unlock]; | |
| 571 | + | |
| 572 | + if(!_displayLink){ | |
| 573 | + SEL dpCB = @selector(displayLinkCallBack:); | |
| 574 | + _displayLink = [CADisplayLink displayLinkWithTarget:self | |
| 575 | + selector:dpCB]; | |
| 576 | + [_displayLink addToRunLoop:[NSRunLoop currentRunLoop] | |
| 577 | + forMode:NSRunLoopCommonModes]; | |
| 578 | + } | |
| 579 | +} | |
| 580 | + | |
| 581 | +- (void)updateAnimateLogo { | |
| 582 | + if (_animateDecoder==nil) { | |
| 583 | + return; | |
| 584 | + } | |
| 585 | + [_dlLock lock]; | |
| 586 | + YYImageFrame* frame = [_animateDecoder frameAtIndex:_animateIdx | |
| 587 | + decodeForDisplay:NO]; | |
| 588 | + if (frame.image) { | |
| 589 | + _kitCN.watermark.logoPic = [[GPUImagePicture alloc] initWithImage:frame.image]; | |
| 590 | + } | |
| 591 | + _animateIdx = (_animateIdx+1)%_animateDecoder.frameCount; | |
| 592 | + [_dlLock unlock]; | |
| 593 | +} | |
| 594 | + | |
| 595 | +- (void)displayLinkCallBack:(CADisplayLink *)link { | |
| 596 | + dispatch_async( dispatch_get_global_queue(0, 0), ^(){ | |
| 597 | + if (_animateDecoder) { | |
| 598 | + _dlTime += link.duration; | |
| 599 | + // 读取 图像的 duration 来决定下一帧的刷新时间 | |
| 600 | + // 也可以固定设置为一个值来调整动画的快慢程度 | |
| 601 | + NSTimeInterval delay = [_animateDecoder frameDurationAtIndex:_animateIdx]; | |
| 602 | + if (delay < 0.04) { | |
| 603 | + delay = 0.04; | |
| 604 | + } | |
| 605 | + if (_dlTime < delay) return; | |
| 606 | + _dlTime -= delay; | |
| 607 | + [self updateAnimateLogo]; | |
| 608 | + } | |
| 609 | + }); | |
| 610 | +} | |
| 611 | + | |
| 612 | +#pragma mark - | |
| 613 | +#pragma mark - nitification | |
| 614 | +- (void)addObservers | |
| 615 | +{ | |
| 616 | + [[NSNotificationCenter defaultCenter] addObserver:self | |
| 617 | + selector:@selector(captureStateChange) | |
| 618 | + name:CNLiveCaptureStateDidChangeNotification | |
| 619 | + object:nil]; | |
| 620 | + | |
| 621 | + [[NSNotificationCenter defaultCenter] addObserver:self | |
| 622 | + selector:@selector(streamStateChange) | |
| 623 | + name:CNLiveStreamerStateDidChangeNotification | |
| 624 | + object:nil]; | |
| 625 | + | |
| 626 | + [[NSNotificationCenter defaultCenter] addObserver:self | |
| 627 | + selector:@selector(reconnectStatusChanged) | |
| 628 | + name:CNLiveStreamerReconnectStatusChangedNotification | |
| 629 | + object:nil]; | |
| 630 | + | |
| 631 | + [[NSNotificationCenter defaultCenter] addObserver:self | |
| 632 | + selector:@selector(enterBg) | |
| 633 | + name:UIApplicationDidEnterBackgroundNotification | |
| 634 | + object:nil]; | |
| 635 | + | |
| 636 | + [[NSNotificationCenter defaultCenter] addObserver:self | |
| 637 | + selector:@selector(becameActive) | |
| 638 | + name:UIApplicationDidBecomeActiveNotification | |
| 639 | + object:nil]; | |
| 640 | +} | |
| 641 | + | |
| 642 | +#pragma mark - notification | |
| 643 | + | |
| 644 | +- (void)enterBg | |
| 645 | +{ | |
| 646 | +// [_kitCN appEnterBackground]; | |
| 647 | +} | |
| 648 | + | |
| 649 | +- (void)becameActive | |
| 650 | +{ | |
| 651 | +// [_kitCN appBecomeActive]; | |
| 652 | +} | |
| 653 | + | |
| 654 | +- (void)captureStateChange | |
| 655 | +{ | |
| 656 | + | |
| 657 | + if ( _kitCN.captureState == CNLiveCaptureStateIdle){ | |
| 658 | + //初始化时状态为空闲 | |
| 659 | + _stateLab.text = @"CNLiveCaptureStateIdle"; | |
| 660 | + | |
| 661 | + return; | |
| 662 | + } | |
| 663 | + else if (_kitCN.captureState == CNLiveCaptureStateCapturing ) { | |
| 664 | + //设备工作中 | |
| 665 | + _stateLab.text = @"CNLiveCaptureStateCapturing"; | |
| 666 | + | |
| 667 | + return; | |
| 668 | + } | |
| 669 | + else if (_kitCN.captureState == CNLiveCaptureStateClosingCapture ) { | |
| 670 | + //关闭采集设备中 | |
| 671 | + _stateLab.text = @"CNLiveCaptureStateClosingCapture"; | |
| 672 | + | |
| 673 | + return; | |
| 674 | + } | |
| 675 | + else if (_kitCN.captureState == CNLiveCaptureStateDevAuthDenied ) { | |
| 676 | + //设备授权被拒绝 | |
| 677 | + NSLog(@"---------CNLiveCaptureStateDevAuthDenied"); | |
| 678 | + _stateLab.text = @"camera/mic Authorization Denied"; | |
| 679 | + | |
| 680 | + return; | |
| 681 | + } | |
| 682 | + else if (_kitCN.captureState == CNLiveCaptureStateParameterError ) { | |
| 683 | + // 参数错误,无法打开 | |
| 684 | + NSLog(@"---------CNLiveCaptureStateParameterError"); | |
| 685 | + _stateLab.text = @"capture devices ParameterError"; | |
| 686 | + | |
| 687 | + return; | |
| 688 | + } | |
| 689 | + else if (_kitCN.captureState == CNLiveCaptureStateDevBusy ) { | |
| 690 | + //设备正忙,请稍后尝试 | |
| 691 | + NSLog(@"---------CNLiveCaptureStateDevBusy"); | |
| 692 | + _stateLab.text = @"device busy, try later"; | |
| 693 | + | |
| 694 | + } | |
| 695 | +} | |
| 696 | + | |
| 697 | +- (void)streamStateChange | |
| 698 | +{ | |
| 699 | + | |
| 700 | + if (_kitCN.streamState == CNLiveStreamStateIdle) { | |
| 701 | + NSLog(@"---------CNLiveStreamStateIdle"); | |
| 702 | + _stateLab.text = @"CNLiveStreamStateIdle"; | |
| 703 | + } | |
| 704 | + | |
| 705 | + if (_kitCN.streamState == CNLiveStreamStateConnected) { | |
| 706 | + _startLiveBtn.selected = YES; | |
| 707 | + NSLog(@"---------CNLiveStreamStateConnected"); | |
| 708 | + _stateLab.text = [NSString stringWithFormat:@"CNLiveStreamStateConnected------%@",_hostURL]; | |
| 709 | + } | |
| 710 | + | |
| 711 | + if (_kitCN.streamState == CNLiveStreamStateConnecting) { | |
| 712 | + NSLog(@"---------CNLiveStreamStateConnecting"); | |
| 713 | + _stateLab.text = @"CNLiveStreamStateConnecting"; | |
| 714 | + } | |
| 715 | + | |
| 716 | + //推流出错 | |
| 717 | + if (_kitCN.streamState == CNLiveStreamStateError) { | |
| 718 | + NSLog(@"---------CNLiveStreamStateError"); | |
| 719 | + [self onStreamError]; | |
| 720 | + } | |
| 721 | + | |
| 722 | + //断开推流 | |
| 723 | + if ( _kitCN.streamState == CNLiveStreamStateDisconnecting) { | |
| 724 | + NSLog(@"---------CNLiveStreamStateDisconnecting"); | |
| 725 | + _stateLab.text = @"CNLiveStreamStateDisconnecting"; | |
| 726 | + | |
| 727 | + } | |
| 728 | + | |
| 729 | + //结束推流成功 | |
| 730 | + if ( _kitCN.streamState == CNLiveStopStreamSuccess) { | |
| 731 | + NSLog(@"---------CNLiveStopStreamSuccess"); | |
| 732 | + _stateLab.text = @"CNLiveStopStreamSuccess"; | |
| 733 | + | |
| 734 | + } | |
| 735 | +} | |
| 736 | + | |
| 737 | +- (void)onStreamError { | |
| 738 | + | |
| 739 | + _startLiveBtn.selected = NO; | |
| 740 | + | |
| 741 | + CNLiveStreamErrorCode err = _kitCN.streamErrorCode; | |
| 742 | + [self toast:[NSString stringWithFormat:@"error ------ %lu",(unsigned long)err]]; | |
| 743 | + | |
| 744 | + NSLog(@"onErr: %lu [%@]", (unsigned long) err, _stateLab.text); | |
| 745 | + | |
| 746 | + if ( CNLiveStreamErrorCode_CNLiveAUTHFAILED == err ) { | |
| 747 | + _stateLab.text = @"SDK auth failed, \npls check ak/sk"; | |
| 748 | + } | |
| 749 | + else if ( CNLiveStreamErrorCode_CODEC_OPEN_FAILED == err) { | |
| 750 | + _stateLab.text = @"Selected Codec not supported \n in this version"; | |
| 751 | + } | |
| 752 | + else if ( CNLiveStreamErrorCode_CONNECT_FAILED == err) { | |
| 753 | + _stateLab.text = @"Connecting error, pls check host url \nor network"; | |
| 754 | + } | |
| 755 | + else if ( CNLiveStreamErrorCode_CONNECT_BREAK == err) { | |
| 756 | + _stateLab.text = @"Connection break"; | |
| 757 | + } | |
| 758 | + else if ( CNLiveStreamErrorCode_ABNORMAL == err) { | |
| 759 | + _stateLab.text = @"CNLiveStreamErrorCode_ABNORMAL"; | |
| 760 | + [self toast:@"推流异常中断~~"]; | |
| 761 | + _startLiveBtn.selected = NO; | |
| 762 | + | |
| 763 | + } else if (err == CNLiveStreamErrorCode_CODEC_OPEN_FAILED) { | |
| 764 | + NSLog(@"video codec open failed, try software codec"); | |
| 765 | + _kitCN.streamerBase.videoCodec = CNLiveVideoCodec_VT264; | |
| 766 | +// [self tryReconnect]; | |
| 767 | + } | |
| 768 | + else { | |
| 769 | + | |
| 770 | + } | |
| 771 | + | |
| 772 | + // 断网重连 | |
| 773 | + if (err == CNLiveStreamErrorCode_CONNECT_BREAK || err == CNLiveStreamErrorCode_AV_SYNC_ERROR) { | |
| 774 | +// [self tryReconnect]; | |
| 775 | + } | |
| 776 | +} | |
| 777 | + | |
| 778 | +- (void) tryReconnect | |
| 779 | +{ | |
| 780 | + dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)); | |
| 781 | + dispatch_after(delay, dispatch_get_main_queue(), ^{ | |
| 782 | + | |
| 783 | + NSLog(@"try again"); | |
| 784 | + | |
| 785 | + [_kitCN stopStream]; | |
| 786 | + | |
| 787 | + if (_isAuthLive) { | |
| 788 | + | |
| 789 | + [_kitCN startStream:^{ | |
| 790 | + NSLog(@"开启推流成功 ------- success"); | |
| 791 | + _startLiveBtn.selected = YES; | |
| 792 | + | |
| 793 | + } failure:^(NSDictionary *errorDic) { | |
| 794 | + [self toast:errorDic[@"errorMessage"]]; | |
| 795 | + _startLiveBtn.selected = NO; | |
| 796 | + }]; | |
| 797 | + | |
| 798 | + }else{ | |
| 799 | + [_kitCN startStream:_hostURL]; | |
| 800 | + } | |
| 801 | + }); | |
| 802 | +} | |
| 803 | + | |
| 804 | +- (void)reconnectStatusChanged { | |
| 805 | + switch (_kitCN.reconnectStatus) { | |
| 806 | + case CNLiveReconnectStatusStart: | |
| 807 | + [_loadingView setLoadingViewStyle:LoadingViewStyleStartLoading]; | |
| 808 | + NSLog(@"开始自动重连~~~~"); | |
| 809 | + break; | |
| 810 | + | |
| 811 | + case CNLiveReconnectStatusSuccess: | |
| 812 | + [_loadingView setLoadingViewStyle:LoadingViewStyleStopLoading]; | |
| 813 | + NSLog(@"自动重连成功~~~~"); | |
| 814 | + break; | |
| 815 | + | |
| 816 | + case CNLiveReconnectStatusFailed: | |
| 817 | + [self toast:@"自动重连失败~~~~"]; | |
| 818 | + [_loadingView setLoadingViewStyle:LoadingViewStyleRetry]; | |
| 819 | + break; | |
| 820 | + | |
| 821 | + default: | |
| 822 | + break; | |
| 823 | + } | |
| 824 | +} | |
| 825 | + | |
| 826 | +- (void)onBypassRecordStateChange:(CNLiveRecordState)newState { | |
| 827 | + if (newState == CNLiveRecordStateRecording){ | |
| 828 | + NSLog(@"start bypass record"); | |
| 829 | + } | |
| 830 | + else if (newState == CNLiveRecordStateStopped) { | |
| 831 | + NSLog(@"stop bypass record"); | |
| 832 | + [self saveVideoToAlbum:_bypassRecFile]; | |
| 833 | + _moreFuncsView.bypassRecord.on = NO; | |
| 834 | + } | |
| 835 | + else if (newState == CNLiveRecordStateError) { | |
| 836 | + NSLog(@"bypass record error %@", _kitCN.streamerBase.bypassRecordErrorName); | |
| 837 | + } | |
| 838 | +} | |
| 839 | + | |
| 840 | +#pragma mark - | |
| 841 | +#pragma mark - LoadingViewDelegate | |
| 842 | +- (void)loadingView:(LoadingView *)loadingViewRetryAction { | |
| 843 | + [self startStreaming:_startLiveBtn]; | |
| 844 | +} | |
| 845 | + | |
| 846 | +#pragma mark - | |
| 847 | +#pragma mark - | |
| 848 | +/** | |
| 849 | + @abstract 将UI的坐标转换成相机坐标 | |
| 850 | + */ | |
| 851 | +- (CGPoint)convertToPointOfInterestFromViewCoordinates:(CGPoint)viewCoordinates | |
| 852 | +{ | |
| 853 | + CGPoint pointOfInterest = CGPointMake(.5f, .5f); | |
| 854 | + CGSize frameSize = self.view.frame.size; | |
| 855 | + CGSize apertureSize = [_kitCN captureDimension]; | |
| 856 | + CGPoint point = viewCoordinates; | |
| 857 | + CGFloat apertureRatio = apertureSize.height / apertureSize.width; | |
| 858 | + CGFloat viewRatio = frameSize.width / frameSize.height; | |
| 859 | + CGFloat xc = .5f; | |
| 860 | + CGFloat yc = .5f; | |
| 861 | + | |
| 862 | + if (viewRatio > apertureRatio) { | |
| 863 | + CGFloat y2 = frameSize.height; | |
| 864 | + CGFloat x2 = frameSize.height * apertureRatio; | |
| 865 | + CGFloat x1 = frameSize.width; | |
| 866 | + CGFloat blackBar = (x1 - x2) / 2; | |
| 867 | + if (point.x >= blackBar && point.x <= blackBar + x2) { | |
| 868 | + xc = point.y / y2; | |
| 869 | + yc = 1.f - ((point.x - blackBar) / x2); | |
| 870 | + } | |
| 871 | + }else { | |
| 872 | + CGFloat y2 = frameSize.width / apertureRatio; | |
| 873 | + CGFloat y1 = frameSize.height; | |
| 874 | + CGFloat x2 = frameSize.width; | |
| 875 | + CGFloat blackBar = (y1 - y2) / 2; | |
| 876 | + if (point.y >= blackBar && point.y <= blackBar + y2) { | |
| 877 | + xc = ((point.y - blackBar) / y2); | |
| 878 | + yc = 1.f - (point.x / x2); | |
| 879 | + } | |
| 880 | + } | |
| 881 | + pointOfInterest = CGPointMake(xc, yc); | |
| 882 | + return pointOfInterest; | |
| 883 | +} | |
| 884 | + | |
| 885 | +- (void)toast:(NSString*)message | |
| 886 | +{ | |
| 887 | + | |
| 888 | + UIAlertView *toast = [[UIAlertView alloc] initWithTitle:nil | |
| 889 | + message:message | |
| 890 | + delegate:nil | |
| 891 | + cancelButtonTitle:nil | |
| 892 | + otherButtonTitles:nil, nil]; | |
| 893 | + [toast show]; | |
| 894 | + double duration = 2.5; | |
| 895 | + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ | |
| 896 | + [toast dismissWithClickedButtonIndex:0 animated:NO]; | |
| 897 | + }); | |
| 898 | +} | |
| 899 | + | |
| 900 | + | |
| 901 | +- (UIButton *)addTextButton:(NSString *)title | |
| 902 | + selectedTitle:(NSString *)selectedTitle | |
| 903 | + frame:(CGRect)frame | |
| 904 | + radius:(CGFloat)radius | |
| 905 | + action:(SEL)action { | |
| 906 | + UIButton * button; | |
| 907 | + button = [UIButton buttonWithType:UIButtonTypeCustom]; | |
| 908 | + button.frame = frame; | |
| 909 | + [button setTitle: title forState: UIControlStateNormal]; | |
| 910 | + [button setTitle:selectedTitle forState:UIControlStateSelected]; | |
| 911 | + [button addTarget:self action:action forControlEvents:UIControlEventTouchUpInside]; | |
| 912 | + button.titleLabel.font = [UIFont systemFontOfSize:15]; | |
| 913 | + [button setTitleColor:[UIColor colorWithRed:23/255.0 green:110/255.0 blue:254/255.0 alpha:1] forState:UIControlStateNormal]; | |
| 914 | + button.layer.cornerRadius = radius; | |
| 915 | + button.layer.masksToBounds = YES; | |
| 916 | + button.layer.borderColor = [UIColor blackColor].CGColor; | |
| 917 | + button.layer.borderWidth = 1; | |
| 918 | + [self.view addSubview:button]; | |
| 919 | + return button; | |
| 920 | + | |
| 921 | +} | |
| 922 | + | |
| 923 | +- (UIButton *)addImageBtn:(UIImage *)normalImg | |
| 924 | + selectedImg:(UIImage *)selectedImg | |
| 925 | + frame:(CGRect)frame | |
| 926 | + action:(SEL)action { | |
| 927 | + UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; | |
| 928 | + button.frame = frame; | |
| 929 | + [button setImage:normalImg forState:UIControlStateNormal]; | |
| 930 | + [button setImage:selectedImg forState:UIControlStateSelected]; | |
| 931 | + [button addTarget:self action:action forControlEvents:UIControlEventTouchUpInside]; | |
| 932 | + [self.view addSubview:button]; | |
| 933 | + return button; | |
| 934 | +} | |
| 935 | + | |
| 936 | + | |
| 937 | +//保存视频到相簿 | |
| 938 | +- (void) saveVideoToAlbum: (NSString*) path { | |
| 939 | + NSFileManager *fileManager = [NSFileManager defaultManager]; | |
| 940 | + if (![fileManager fileExistsAtPath:path]) { | |
| 941 | + return; | |
| 942 | + } | |
| 943 | + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ | |
| 944 | + if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(path)) { | |
| 945 | + SEL onDone = @selector(video:didFinishSavingWithError:contextInfo:); | |
| 946 | + UISaveVideoAtPathToSavedPhotosAlbum(path, self, onDone, nil); | |
| 947 | + } | |
| 948 | + }); | |
| 949 | +} | |
| 950 | + | |
| 951 | +//删除文件,保证保存到相册里面的视频时间是最新的 | |
| 952 | +-(void)deleteFile:(NSString *)file{ | |
| 953 | + NSFileManager *fileManager = [NSFileManager defaultManager]; | |
| 954 | + if ([fileManager fileExistsAtPath:file]) { | |
| 955 | + [fileManager removeItemAtPath:file error:nil]; | |
| 956 | + } | |
| 957 | +} | |
| 958 | + | |
| 959 | +//保存mp4文件完成时的回调 | |
| 960 | +- (void)video:(NSString *)videoPath didFinishSavingWithError:(NSError *)error | |
| 961 | + contextInfo:(void *)contextInfo { | |
| 962 | + NSString *message; | |
| 963 | + if (!error) { | |
| 964 | + message = @"Save album success!"; | |
| 965 | + } | |
| 966 | + else { | |
| 967 | + message = @"Failed to save the album!"; | |
| 968 | + } | |
| 969 | + [self toast:message]; | |
| 970 | +} | |
| 971 | + | |
| 972 | +#pragma mark - GetMethod | |
| 973 | + | |
| 974 | +- (UIView *)captureView | |
| 975 | +{ | |
| 976 | + if (!_captureView) { | |
| 977 | + _captureView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)]; | |
| 978 | + _captureView.backgroundColor = [UIColor whiteColor]; | |
| 979 | + } | |
| 980 | + return _captureView; | |
| 981 | +} | |
| 982 | + | |
| 983 | +- (UILabel *)stateLab | |
| 984 | +{ | |
| 985 | + if (!_stateLab) { | |
| 986 | + _stateLab = [[UILabel alloc] initWithFrame:CGRectMake(0, Height/2-50, Width, 100)]; | |
| 987 | + _stateLab.backgroundColor = [UIColor clearColor]; | |
| 988 | + _stateLab.numberOfLines = 0; | |
| 989 | + _stateLab.textColor = [UIColor redColor]; | |
| 990 | + } | |
| 991 | + return _stateLab; | |
| 992 | +} | |
| 993 | + | |
| 994 | +- (FilterFunctionView *)filterView | |
| 995 | +{ | |
| 996 | + if (!_filterView) { | |
| 997 | + _filterView = [[FilterFunctionView alloc] initWithFrame:CGRectMake(0, 80, Width, 240)]; | |
| 998 | + _filterView.hidden = YES; | |
| 999 | + } | |
| 1000 | + return _filterView; | |
| 1001 | +} | |
| 1002 | + | |
| 1003 | +- (AudioCfgView *)audioCfgView | |
| 1004 | +{ | |
| 1005 | + if (!_audioCfgView) { | |
| 1006 | + _audioCfgView = [[AudioCfgView alloc] initWithFrame:CGRectMake(0, 80, Width, 200)]; | |
| 1007 | + _audioCfgView.hidden = YES; | |
| 1008 | + } | |
| 1009 | + return _audioCfgView; | |
| 1010 | +} | |
| 1011 | + | |
| 1012 | +- (MoreFunctionsView *)moreFuncsView | |
| 1013 | +{ | |
| 1014 | + if (!_moreFuncsView) { | |
| 1015 | + _moreFuncsView = [[MoreFunctionsView alloc] initWithFrame:CGRectMake(0, 80, Width, 240)]; | |
| 1016 | + [_moreFuncsView.bypassRecord addTarget:self action:@selector(bypassRecordOn:) forControlEvents:UIControlEventValueChanged]; | |
| 1017 | + [_moreFuncsView.floatingWindowBtn addTarget:self action:@selector(floatingWindowBtnAction) forControlEvents:UIControlEventTouchUpInside]; | |
| 1018 | + _moreFuncsView.hidden = YES; | |
| 1019 | + } | |
| 1020 | + return _moreFuncsView; | |
| 1021 | +} | |
| 1022 | + | |
| 1023 | +- (LoadingView *)loadingView | |
| 1024 | +{ | |
| 1025 | + if (!_loadingView) { | |
| 1026 | + _loadingView = [[LoadingView alloc] initWithFrame:CGRectMake(0, 0, 70, 70)]; | |
| 1027 | + _loadingView.center = self.view.center; | |
| 1028 | + [_loadingView setLoadingViewStyle:LoadingViewStyleStopLoading]; | |
| 1029 | + _loadingView.delegate = self; | |
| 1030 | + } | |
| 1031 | + return _loadingView; | |
| 1032 | +} | |
| 1033 | + | |
| 1034 | +- (void)dealloc | |
| 1035 | +{ | |
| 1036 | + [_kitCN quitStreaming]; | |
| 1037 | + self.kitCN = nil; | |
| 1038 | + [[NSNotificationCenter defaultCenter] removeObserver:self]; | |
| 1039 | + | |
| 1040 | + NSLog(@"StreamerDetailViewController dealloc"); | |
| 1041 | + | |
| 1042 | +} | |
| 1043 | + | |
| 1044 | +- (void)didReceiveMemoryWarning { | |
| 1045 | + [super didReceiveMemoryWarning]; | |
| 1046 | + // Dispose of any resources that can be recreated. | |
| 1047 | +} | |
| 1048 | + | |
| 1049 | +/* | |
| 1050 | + #pragma mark - Navigation | |
| 1051 | + | |
| 1052 | + // In a storyboard-based application, you will often want to do a little preparation before navigation | |
| 1053 | + - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { | |
| 1054 | + // Get the new view controller using [segue destinationViewController]. | |
| 1055 | + // Pass the selected object to the new view controller. | |
| 1056 | + } | |
| 1057 | + */ | |
| 1058 | + | |
| 1059 | +@end | ... | ... |
Example/CNLivePlayer/Streamer/house.gif
0 → 100644
351 Bytes