Authored by 盖剑秋

Fix bugs and add new SDK from Tencent.

... ... @@ -29,6 +29,7 @@
2E5FA8941D06DB2F00920FB4 /* YH_ChannelCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 2E5FA8931D06DB2F00920FB4 /* YH_ChannelCell.m */; };
2E64AB941D08099E004307A3 /* launchimage1@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 2E64AB921D08099E004307A3 /* launchimage1@2x.png */; };
2E64AB951D08099E004307A3 /* launchimage1@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 2E64AB931D08099E004307A3 /* launchimage1@3x.png */; };
2E6A3D9D1D18D407001A0E59 /* libstdc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 2E6A3D9C1D18D406001A0E59 /* libstdc++.tbd */; };
2EA13A2A1D05733B0037C9EB /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2EA139F51D05733B0037C9EB /* AppDelegate.m */; };
2EA13A2B1D05733B0037C9EB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2EA139F61D05733B0037C9EB /* Assets.xcassets */; };
2EA13A2C1D05733B0037C9EB /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2EA139F71D05733B0037C9EB /* LaunchScreen.storyboard */; };
... ... @@ -36,7 +37,6 @@
2EA13A2E1D05733B0037C9EB /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 2EA139FB1D05733B0037C9EB /* Info.plist */; };
2EA13A2F1D05733B0037C9EB /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 2EA139FC1D05733B0037C9EB /* main.m */; };
2EA13A301D05733B0037C9EB /* PlayController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2EA139FE1D05733B0037C9EB /* PlayController.m */; };
2EA13A311D05733B0037C9EB /* PublishController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2EA13A001D05733B0037C9EB /* PublishController.m */; };
2EA13A321D05733B0037C9EB /* adjust.png in Resources */ = {isa = PBXBuildFile; fileRef = 2EA13A021D05733B0037C9EB /* adjust.png */; };
2EA13A331D05733B0037C9EB /* background@2x.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 2EA13A031D05733B0037C9EB /* background@2x.jpg */; };
2EA13A341D05733B0037C9EB /* beauty.png in Resources */ = {isa = PBXBuildFile; fileRef = 2EA13A041D05733B0037C9EB /* beauty.png */; };
... ... @@ -72,7 +72,6 @@
2EA13A541D05733B0037C9EB /* tab.png in Resources */ = {isa = PBXBuildFile; fileRef = 2EA13A241D05733B0037C9EB /* tab.png */; };
2EA13A551D05733B0037C9EB /* tab2.png in Resources */ = {isa = PBXBuildFile; fileRef = 2EA13A251D05733B0037C9EB /* tab2.png */; };
2EA13A561D05733B0037C9EB /* white.png in Resources */ = {isa = PBXBuildFile; fileRef = 2EA13A261D05733B0037C9EB /* white.png */; };
2EA13A571D05733B0037C9EB /* ScanQRController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2EA13A281D05733B0037C9EB /* ScanQRController.mm */; };
2EA13A5B1D0573AB0037C9EB /* TXRTMPSDK.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2EA13A591D05736B0037C9EB /* TXRTMPSDK.framework */; };
2EEAD4BE1D112D04003EE0E9 /* GCDAsyncSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 2EEAD4BB1D112D04003EE0E9 /* GCDAsyncSocket.m */; };
2EEAD4BF1D112D04003EE0E9 /* GCDAsyncSocket+SocketHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 2EEAD4BD1D112D04003EE0E9 /* GCDAsyncSocket+SocketHandler.m */; };
... ... @@ -104,6 +103,7 @@
2E5FA8931D06DB2F00920FB4 /* YH_ChannelCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YH_ChannelCell.m; sourceTree = "<group>"; };
2E64AB921D08099E004307A3 /* launchimage1@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "launchimage1@2x.png"; sourceTree = "<group>"; };
2E64AB931D08099E004307A3 /* launchimage1@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "launchimage1@3x.png"; sourceTree = "<group>"; };
2E6A3D9C1D18D406001A0E59 /* libstdc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libstdc++.tbd"; path = "usr/lib/libstdc++.tbd"; sourceTree = SDKROOT; };
2EA139F41D05733B0037C9EB /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
2EA139F51D05733B0037C9EB /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
2EA139F61D05733B0037C9EB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
... ... @@ -113,8 +113,6 @@
2EA139FC1D05733B0037C9EB /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
2EA139FD1D05733B0037C9EB /* PlayController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlayController.h; sourceTree = "<group>"; };
2EA139FE1D05733B0037C9EB /* PlayController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PlayController.m; sourceTree = "<group>"; };
2EA139FF1D05733B0037C9EB /* PublishController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PublishController.h; sourceTree = "<group>"; };
2EA13A001D05733B0037C9EB /* PublishController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PublishController.m; sourceTree = "<group>"; };
2EA13A021D05733B0037C9EB /* adjust.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = adjust.png; sourceTree = "<group>"; };
2EA13A031D05733B0037C9EB /* background@2x.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "background@2x.jpg"; sourceTree = "<group>"; };
2EA13A041D05733B0037C9EB /* beauty.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = beauty.png; sourceTree = "<group>"; };
... ... @@ -150,8 +148,6 @@
2EA13A241D05733B0037C9EB /* tab.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = tab.png; sourceTree = "<group>"; };
2EA13A251D05733B0037C9EB /* tab2.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = tab2.png; sourceTree = "<group>"; };
2EA13A261D05733B0037C9EB /* white.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = white.png; sourceTree = "<group>"; };
2EA13A271D05733B0037C9EB /* ScanQRController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScanQRController.h; sourceTree = "<group>"; };
2EA13A281D05733B0037C9EB /* ScanQRController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ScanQRController.mm; sourceTree = "<group>"; };
2EA13A591D05736B0037C9EB /* TXRTMPSDK.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TXRTMPSDK.framework; path = YohoLive/TXRTMPSDK.framework; sourceTree = "<group>"; };
2EEAD4BA1D112D04003EE0E9 /* GCDAsyncSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDAsyncSocket.h; sourceTree = "<group>"; };
2EEAD4BB1D112D04003EE0E9 /* GCDAsyncSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDAsyncSocket.m; sourceTree = "<group>"; };
... ... @@ -170,6 +166,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
2E6A3D9D1D18D407001A0E59 /* libstdc++.tbd in Frameworks */,
2EA13A5B1D0573AB0037C9EB /* TXRTMPSDK.framework in Frameworks */,
EFF834691CEB638B00345113 /* CoreTelephony.framework in Frameworks */,
A09B25771CE57CAF00E68E28 /* SystemConfiguration.framework in Frameworks */,
... ... @@ -183,6 +180,7 @@
14DBC8FCBFC905B673B5534D /* Frameworks */ = {
isa = PBXGroup;
children = (
2E6A3D9C1D18D406001A0E59 /* libstdc++.tbd */,
A2F123EA9030672A0EFEF6CC /* libPods.a */,
);
name = Frameworks;
... ... @@ -222,11 +220,7 @@
2EA139FC1D05733B0037C9EB /* main.m */,
2EA139FD1D05733B0037C9EB /* PlayController.h */,
2EA139FE1D05733B0037C9EB /* PlayController.m */,
2EA139FF1D05733B0037C9EB /* PublishController.h */,
2EA13A001D05733B0037C9EB /* PublishController.m */,
2EA13A011D05733B0037C9EB /* resource */,
2EA13A271D05733B0037C9EB /* ScanQRController.h */,
2EA13A281D05733B0037C9EB /* ScanQRController.mm */,
);
path = YohoLive;
sourceTree = "<group>";
... ... @@ -501,9 +495,7 @@
2E2E2D791D0E8B290067D118 /* YH_HTTPRequestSerializer.m in Sources */,
2E2E2D7C1D0E8BD90067D118 /* NSString+M16String.m in Sources */,
2EA13A2F1D05733B0037C9EB /* main.m in Sources */,
2EA13A571D05733B0037C9EB /* ScanQRController.mm in Sources */,
2E5FA8911D06D2FD00920FB4 /* YH_ChannelModel.m in Sources */,
2EA13A311D05733B0037C9EB /* PublishController.m in Sources */,
2E5FA8941D06DB2F00920FB4 /* YH_ChannelCell.m in Sources */,
2E4D5FC21D057C6100D508BB /* YH_RootViewController.m in Sources */,
2EA13A2A1D05733B0037C9EB /* AppDelegate.m in Sources */,
... ...
... ... @@ -8,7 +8,6 @@
#import "AppDelegate.h"
#include "PlayController.h"
#include "PublishController.h"
#ifdef CRASH_REPORT
#import <Bugly/Bugly.h>
#endif
... ...
... ... @@ -18,19 +18,23 @@
#import "AFHTTPSessionManager.h"
#import "YH_HTTPRequestSerializer.h"
#import "GCDAsyncSocket+SocketHandler.h"
#import "AFNetworkReachabilityManager.h"
static const NSInteger socketMaxRetryCount = 3;
//static const NSInteger socketMaxRetryCount = 3;
// 清晰度定义
#define HD_LEVEL_720P 1 // 1280 * 720
#define HD_LEVEL_640 2 // 640 * 360
#define HD_LEVEL_640_PLUS 3 // 640 * 360 且开启码率自适应
#define HD_LEVEL_540P 2 // 960 * 560
#define HD_LEVEL_360P 3 // 640 * 360
#define HD_LEVEL_360_PLUS 4 // 640 * 360 且开启码率自适应
#define RTMP_PUBLISH_URL @"rtmp://2718.livepush.myqcloud.com/live/2718_01973243308211e6a2cba4dcbef5e35a?bizid=2718" //调试期间您可以修改之以避免输入地址的麻烦
#define SOCKET_LIVE_HOST @"123.206.65.220"
#define SOCKET_LIVE_PORT 9512
#define SOCKET_COMMAND @"cmd"
@interface YH_RootViewController ()<TXLivePushListener, UITableViewDelegate, UITableViewDataSource>
@property (nonatomic, strong) TXLivePush *livePush;
... ... @@ -59,6 +63,7 @@ static const NSInteger socketMaxRetryCount = 3;
@property (nonatomic, strong) UISlider *sdWhitening;
@property (nonatomic, strong) UIView *vHD;
@property (nonatomic, strong) UIButton *radioBtnHD;
@property (nonatomic, strong) UIButton *radioBtnHD2;
@property (nonatomic, strong) UIButton *radioBtnSD;
@property (nonatomic, strong) UIButton *radioBtnAUTO;
... ... @@ -150,14 +155,14 @@ static const NSInteger socketMaxRetryCount = 3;
// if ([responseObject isKindOfClass:[NSDictionary class]]) {
// id data = responseObject[@"data"];
// if (![data isKindOfClass:[NSArray class]]) {
// [self toastTip:@"data formmat error"];
// [self toastTip:@"没有可用直播间"];
// return;
// }
// NSMutableArray *tempAry = @[].mutableCopy;
// [data enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
// if (![obj isKindOfClass:[NSDictionary class]]) {
// *stop = YES;
// [self toastTip:@"data formmat error"];
// [self toastTip:@"没有可用直播间"];
// }
// YH_ChannelModel *model = [YH_ChannelModel new];
// model.roomTitle = obj[@"name"];
... ... @@ -209,29 +214,6 @@ static const NSInteger socketMaxRetryCount = 3;
-(BOOL)startRtmp{
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.responseSerializer.acceptableContentTypes = [manager.responseSerializer.acceptableContentTypes setByAddingObject:@"text/html"];
manager.requestSerializer = [YH_HTTPRequestSerializer new];
NSURLSessionDataTask *task = [manager
GET:@"http://newboys.test.yoho.cn/yohoboyins/v4/qcloud/closeLive"
parameters:@{@"cid":_currentChannel.room?:@"0"}
progress:^(NSProgress * _Nonnull downloadProgress) {
NSLog(@"aaaa");
}
success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSLog(@"bbbb%@",responseObject);
}
failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"ccc");
}];
NSLog(@"%@",task.originalRequest.URL.absoluteString);
_totalTime = 0;
_timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(updateInfoView) userInfo:nil repeats:YES];
[_timer fire];
[self clearLog];
[UIApplication sharedApplication].idleTimerDisabled = YES;//stop lock screen.
NSString* rtmpUrl = _currentChannel.roomURL;
if (rtmpUrl.length == 0) {
... ... @@ -266,26 +248,8 @@ static const NSInteger socketMaxRetryCount = 3;
- (void)stopRtmp {
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.responseSerializer.acceptableContentTypes = [manager.responseSerializer.acceptableContentTypes setByAddingObject:@"text/html"];
manager.requestSerializer = [YH_HTTPRequestSerializer new];
NSURLSessionDataTask *task = [manager
GET:@"http://newboys.test.yoho.cn/yohoboyins/v4/qcloud/closeLive"
parameters:@{@"cid":_currentChannel.room?:@"0"}
progress:NULL
success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSLog(@"bbbb%@",responseObject);
}
failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"ccc");
}];
NSLog(@"%@",task.originalRequest.URL.absoluteString);
[self socketSendEndNotify];//通知结束。
[UIApplication sharedApplication].idleTimerDisabled = NO;
[_timer invalidate];
if(_livePush)
{
[_livePush stopPush];
... ... @@ -312,7 +276,8 @@ static const NSInteger socketMaxRetryCount = 3;
dispatch_async(dispatch_get_main_queue(), ^{
if (EvtID == PUSH_ERR_NET_DISCONNECT) {
[self liveButtonPressed:_liveButton];
[self startRtmp];//不停的重试,只要在用户点击结束之前,都要进行重新连接操作。
// [self liveButtonPressed:_liveButton];
}
long long time = [(NSNumber*)[dict valueForKey:EVT_TIME] longLongValue];
int mil = time % 1000;
... ... @@ -364,10 +329,9 @@ static const NSInteger socketMaxRetryCount = 3;
@"room":_currentChannel.room?:@"666",
@"msg":@(666),//结束时的瞬时在线人数
@"videoLen":_timeLabel.text,
@"uid":@""
};
[_socket writeDataWithParams:params tag:1];
_socketTimer = [NSTimer scheduledTimerWithTimeInterval:0 target:self selector:@selector(socketSendEndNotify) userInfo:nil repeats:YES];
[_socket writeDataWithParams:params tag:2];
} else {
[self connectSocket];
}
... ... @@ -380,12 +344,20 @@ static const NSInteger socketMaxRetryCount = 3;
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port
{
_currentRetryCount = 0;
DLog(@"socket connect success!");
[self socketSendEndNotify];
dispatch_async(dispatch_get_main_queue(), ^{
_currentRetryCount = 0;
DLog(@"socket connect success!");
NSDictionary *params = @{@"cmd":@(1),
@"uid":@"",
@"room":_currentChannel.room?:@"666",
@"name":@"",
@"avatar":@""
};
[_socket writeDataWithParams:params tag:1];
});
}
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err{
... ... @@ -400,14 +372,36 @@ static const NSInteger socketMaxRetryCount = 3;
- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
{
dispatch_async(dispatch_get_main_queue(), ^{
DLog(@"通知结束成功");
[self toastTip:@"通知结束成功"];
[sock disconnect];
_inPushing = NO;
[_socketTimer invalidate];
if (tag == 1) {//登录成功了之后才继续后面的。。。。
[self socketSendEndNotify];
_socketTimer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(socketSendEndNotify) userInfo:nil repeats:YES];
}
});
}
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
dispatch_async(dispatch_get_main_queue(), ^{
NSError *error = nil;
NSDictionary *resDic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
DLog(@"=======%@",resDic);
if (resDic && [resDic.allKeys containsObject:SOCKET_COMMAND]) {
int cmd = [[resDic objectForKey:SOCKET_COMMAND] intValue];
if (cmd == 12) {
dispatch_async(dispatch_get_main_queue(), ^{
DLog(@"通知结束成功");
[self toastTip:@"通知结束成功"];
[sock disconnect];
_inPushing = NO;
[_socketTimer invalidate];
});
}
}
});
}
#pragma mark - Button actions...
- (void)hdPressed:(UIButton *)sender {
... ... @@ -473,6 +467,7 @@ static const NSInteger socketMaxRetryCount = 3;
}
- (void)channelPressed:(UIButton *)sender {
if (!_channels.count) {
[self loadChannelData];
[self toastTip:@"房间加载失败,稍后再试!"];
... ... @@ -517,12 +512,65 @@ static const NSInteger socketMaxRetryCount = 3;
}
- (void)liveButtonPressed:(UIButton *)sender {
if (!_currentChannel) {
[self toastTip:@"请先选择房间"];
return;
}
[self hideAllToolView];
_liveButton.selected = !_liveButton.selected;
if (_liveButton.selected) {
[self startRtmp];
if ([self startRtmp]) {
[self toastTip:@"开始直播"];
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.responseSerializer.acceptableContentTypes = [manager.responseSerializer.acceptableContentTypes setByAddingObject:@"text/html"];
manager.requestSerializer = [YH_HTTPRequestSerializer new];
NSURLSessionDataTask *task = [manager
GET:@"http://newboys.test.yoho.cn/yohoboyins/v4/qcloud/startLive"
parameters:@{@"cid":_currentChannel.room?:@"0"}
progress:^(NSProgress * _Nonnull downloadProgress) {
NSLog(@"aaaa");
}
success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSLog(@"bbbb%@",responseObject);
}
failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"ccc");
}];
NSLog(@"%@",task.originalRequest.URL.absoluteString);
_totalTime = 0;
_timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(updateInfoView) userInfo:nil repeats:YES];
[_timer fire];
[self clearLog];
}
} else {
[self stopRtmp];
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.responseSerializer.acceptableContentTypes = [manager.responseSerializer.acceptableContentTypes setByAddingObject:@"text/html"];
manager.requestSerializer = [YH_HTTPRequestSerializer new];
NSLog(@"%@----%@",_currentChannel.room,_currentChannel.cid);
NSURLSessionDataTask *task = [manager
GET:@"http://newboys.test.yoho.cn/yohoboyins/v4/qcloud/closeLive"
parameters:@{@"cid":_currentChannel.room?:@"0"}
progress:NULL
success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSLog(@"bbbb%@",responseObject);
}
failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"ccc");
}];
NSLog(@"%@",task.originalRequest.URL.absoluteString);
[_timer invalidate];
[self socketSendEndNotify];//通知结束。
}
}
... ... @@ -642,27 +690,34 @@ static const NSInteger socketMaxRetryCount = 3;
txtHD.frame = CGRectMake(0, 0, size.width, 50);
[txtHD setText:@"清晰度"];
[txtHD setFont:[UIFont fontWithName:@"" size:14]];
txtHD.textAlignment = NSTextAlignmentCenter;
[_vHD addSubview:txtHD];
int gap = 30;
int width = (size.width - gap*2 - 20) / 3;
int width = (size.width - gap*3 - 20) / 4;
_radioBtnHD = [UIButton buttonWithType:UIButtonTypeCustom];
_radioBtnHD.frame = CGRectMake(10, 60, width, 40);
[_radioBtnHD setTitle:@"720p" forState:UIControlStateNormal];
[_radioBtnHD addTarget:self action:@selector(changeHD:) forControlEvents:UIControlEventTouchUpInside];
_radioBtnHD2 = [UIButton buttonWithType:UIButtonTypeCustom];
_radioBtnHD2.frame = CGRectMake(10 + gap + width, 60, width, 40);
[_radioBtnHD2 setTitle:@"540p" forState:UIControlStateNormal];
[_radioBtnHD2 addTarget:self action:@selector(changeHD:) forControlEvents:UIControlEventTouchUpInside];
_radioBtnSD = [UIButton buttonWithType:UIButtonTypeCustom];
_radioBtnSD.frame = CGRectMake(10 + gap + width, 60, width, 40);
[_radioBtnSD setTitle:@"640" forState:UIControlStateNormal];
_radioBtnSD.frame = CGRectMake(10 + (gap + width)*2, 60, width, 40);
[_radioBtnSD setTitle:@"360p" forState:UIControlStateNormal];
[_radioBtnSD addTarget:self action:@selector(changeHD:) forControlEvents:UIControlEventTouchUpInside];
_radioBtnAUTO = [UIButton buttonWithType:UIButtonTypeCustom];
_radioBtnAUTO.frame = CGRectMake(size.width - 10 - width, 60, width, 40);
[_radioBtnAUTO setTitle:@"640+" forState:UIControlStateNormal];
[_radioBtnAUTO setTitle:@"360+" forState:UIControlStateNormal];
[_radioBtnAUTO addTarget:self action:@selector(changeHD:) forControlEvents:UIControlEventTouchUpInside];
[_vHD addSubview:_radioBtnHD];
[_vHD addSubview:_radioBtnHD2];
[_vHD addSubview:_radioBtnSD];
[_vHD addSubview:_radioBtnAUTO];
... ... @@ -670,7 +725,7 @@ static const NSInteger socketMaxRetryCount = 3;
[self.view addSubview: _vHD];
// DEMO 默认采用 640 * 360 分辨率, 避免在4S等机型上出现编码不足
int _hd_level = [self isSuitableMachine] ? HD_LEVEL_720P : HD_LEVEL_640;
int _hd_level = [self isSuitableMachine] ? HD_LEVEL_720P : HD_LEVEL_360_PLUS;
[self setHDUI:_hd_level];
}
... ... @@ -679,34 +734,53 @@ static const NSInteger socketMaxRetryCount = 3;
switch (level) {
case HD_LEVEL_720P:
[_radioBtnHD setBackgroundImage:[UIImage imageNamed:@"black"] forState:UIControlStateNormal];
[_radioBtnHD2 setBackgroundImage:[UIImage imageNamed:@"white"] forState:UIControlStateNormal];
[_radioBtnSD setBackgroundImage:[UIImage imageNamed:@"white"] forState:UIControlStateNormal];
[_radioBtnAUTO setBackgroundImage:[UIImage imageNamed:@"white"] forState:UIControlStateNormal];
[_radioBtnHD setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[_radioBtnHD2 setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_radioBtnSD setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_radioBtnAUTO setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_hdButton setTitle:@"高清" forState:UIControlStateNormal];
break;
case HD_LEVEL_640:
case HD_LEVEL_540P:
[_radioBtnHD setBackgroundImage:[UIImage imageNamed:@"white"] forState:UIControlStateNormal];
[_radioBtnHD2 setBackgroundImage:[UIImage imageNamed:@"black"] forState:UIControlStateNormal];
[_radioBtnSD setBackgroundImage:[UIImage imageNamed:@"white"] forState:UIControlStateNormal];
[_radioBtnAUTO setBackgroundImage:[UIImage imageNamed:@"white"] forState:UIControlStateNormal];
[_radioBtnHD setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_radioBtnHD2 setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[_radioBtnSD setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_radioBtnAUTO setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_hdButton setTitle:@"高清" forState:UIControlStateNormal];
break;
case HD_LEVEL_360P:
[_radioBtnHD setBackgroundImage:[UIImage imageNamed:@"white"] forState:UIControlStateNormal];
[_radioBtnHD2 setBackgroundImage:[UIImage imageNamed:@"white"] forState:UIControlStateNormal];
[_radioBtnSD setBackgroundImage:[UIImage imageNamed:@"black"] forState:UIControlStateNormal];
[_radioBtnAUTO setBackgroundImage:[UIImage imageNamed:@"white"] forState:UIControlStateNormal];
[_radioBtnHD setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_radioBtnHD2 setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_radioBtnSD setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[_radioBtnAUTO setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_hdButton setTitle:@"标清" forState:UIControlStateNormal];
break;
case HD_LEVEL_640_PLUS:
case HD_LEVEL_360_PLUS:
[_radioBtnHD setBackgroundImage:[UIImage imageNamed:@"white"] forState:UIControlStateNormal];
[_radioBtnHD2 setBackgroundImage:[UIImage imageNamed:@"white"] forState:UIControlStateNormal];
[_radioBtnSD setBackgroundImage:[UIImage imageNamed:@"white"] forState:UIControlStateNormal];
[_radioBtnAUTO setBackgroundImage:[UIImage imageNamed:@"black"] forState:UIControlStateNormal];
[_radioBtnHD setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_radioBtnHD2 setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_radioBtnSD setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_radioBtnAUTO setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[_hdButton setTitle:@"普清" forState:UIControlStateNormal];
default:
break;
}
}
// iphone 6 及以上机型适合开启720p, 否则20帧的帧率可能无法达到, 这种"流畅不足,清晰有余"的效果并不好
-(BOOL) isSuitableMachine
{
... ... @@ -755,27 +829,33 @@ static const NSInteger socketMaxRetryCount = 3;
_config.videoResolution = [self isSuitableMachine ] ? VIDEO_RESOLUTION_1280_720 : VIDEO_RESOLUTION_960_540;
_config.enableAutoBitrate = NO;
[_livePush setConfig:_config];
} else if ([btn.titleLabel.text isEqualToString:@"640"]) {
_hd_level = HD_LEVEL_640;
}else if ([btn.titleLabel.text isEqualToString:@"540p"]) {
_hd_level = HD_LEVEL_540P;
TXLivePushConfig* _config = _livePush.config;
_config.videoBitratePIN = 800;
_config.videoResolution = VIDEO_RESOLUTION_960_540;
_config.enableAutoBitrate = NO;
[_livePush setConfig:_config];
}else if ([btn.titleLabel.text isEqualToString:@"360p"]) {
_hd_level = HD_LEVEL_360P;
TXLivePushConfig* _config = _livePush.config;
_config.videoBitratePIN = 600;
_config.videoResolution = VIDEO_RESOLUTION_640_360;
_config.enableAutoBitrate = NO;
[_livePush setConfig:_config];
} else if ([btn.titleLabel.text isEqualToString:@"640+"]) {
_hd_level = HD_LEVEL_640_PLUS;
} else if ([btn.titleLabel.text isEqualToString:@"360+"]) {
_hd_level = HD_LEVEL_360_PLUS;
TXLivePushConfig* _config = _livePush.config;
_config.videoBitrateMin = 500;
_config.videoBitrateMax = 1500;
_config.videoBitrateMin = 100;
_config.videoBitrateMax = 1200;
_config.enableAutoBitrate = YES;
_config.videoResolution = VIDEO_RESOLUTION_640_360;
[_livePush setConfig:_config]; // 此模式下设置bitrate无效
}
[self setHDUI:_hd_level];
_vHD.hidden = YES;
... ... @@ -806,6 +886,7 @@ static const NSInteger socketMaxRetryCount = 3;
[_liveButton setTitle:@"开始直播" forState:UIControlStateNormal];
[_liveButton setTitle:@"结束直播" forState:UIControlStateSelected];
_liveButton.titleLabel.font = [UIFont systemFontOfSize:16];
[_liveButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal];
[_channelPannel addSubview:_liveButton];
... ... @@ -916,6 +997,7 @@ static const NSInteger socketMaxRetryCount = 3;
[self initEmojiPannel];
[self initInfoPannel];
UIImage *image = [UIImage imageNamed:@"icon_photoflash"];
_fullScreenButton = [UIButton buttonWithType:UIButtonTypeCustom];
[_fullScreenButton addTarget:self action:@selector(fullScreenPressed:) forControlEvents:UIControlEventTouchUpInside];
[_fullScreenButton setImage:[UIImage imageNamed:@"icon_Exit-Full-Screen"] forState:UIControlStateNormal];
... ... @@ -1027,6 +1109,8 @@ static const NSInteger socketMaxRetryCount = 3;
return;//正在直播的情况下不得选择另外的房间,否则在通知结束的时候无法保证参数正确。。。
}
_currentChannelIndex = indexPath.row;
_currentChannel = _channels[_currentChannelIndex];
[_liveButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_channelTable reloadData];
}
... ...
... ... @@ -5,7 +5,7 @@
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>YOHO!直播</string>
<string>YOHO!推流</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFiles</key>
... ...
... ... @@ -7,7 +7,6 @@
//
#import "PlayController.h"
#import "ScanQRController.h"
#import "TXLivePlayListener.h"
#import "TXRTMPAPI.h"
#import <mach/mach.h>
... ... @@ -327,12 +326,7 @@
-(void) clickScan:(UIButton*) btn
{
[self stopRtmp];
_play_switch = NO;
[_btnPlay setImage:[UIImage imageNamed:@"start"] forState:UIControlStateNormal];
ScanQRController* vc = [[ScanQRController alloc] init];
vc.pvc = self;
[self.navigationController pushViewController:vc animated:NO];
}
... ...
//
// PublishController.h
// RTMPiOSDemo
//
// Created by 蓝鲸 on 16/4/1.
// Copyright © 2016年 tencent. All rights reserved.
//
#import <UIKit/UIKit.h>
//#import <AVFoundation/AVFoundation.h>
#import "TXLivePush.h"
@interface PublishController : UIViewController
{
BOOL _publish_switch;
BOOL _hardware_switch;
BOOL _log_switch;
BOOL _camera_switch;
int _beauty_level;
int _whitening_level;
int _hd_level;
BOOL _torch_switch;
UIButton* _btnPublish;
UIButton* _btnCamera;
UIButton* _btnBeauty;
UIButton* _btnHardware;
UIButton* _btnLog;
UIButton* _btnResolution;
UIButton* _btnTorch;
UIButton* _radioBtnHD;
UIButton* _radioBtnSD;
UIButton* _radioBtnAUTO;
UISlider* _sdBeauty;
UISlider* _sdWhitening;
UIView* _cover;
UIControl* _vBeauty;
UIControl* _vHD;
TXLivePush * _txLivePublisher;
UITextView* _statusView;
UITextView* _logViewEvt;
unsigned long long _startTime;
unsigned long long _lastTime;
//kuentest
NSString* _logMsg;
NSString* _tipsMsg;
NSString* _testPath;
}
@property (nonatomic, retain) UITextField* txtRtmpUrl;
@end
//
// PublishController.m
// RTMPiOSDemo
//
// Created by 蓝鲸 on 16/4/1.
// Copyright © 2016年 tencent. All rights reserved.
//
#import "PublishController.h"
#import "PlayController.h"
#import "ScanQRController.h"
//#import <Foundation/Foundation.h>
//#import "TXLiveSDKTypeDef.h"
#import <sys/types.h>
#import <sys/sysctl.h>
//#import <UIKit/UIKit.h>
//#import <mach/mach.h>
#import "TXRTMPAPI.h"
// 清晰度定义
#define HD_LEVEL_720P 1 // 1280 * 720
#define HD_LEVEL_640 2 // 640 * 360
#define HD_LEVEL_640_PLUS 3 // 640 * 360 且开启码率自适应
#define RTMP_PUBLISH_URL @"请输入或扫二维码获取推流地址" //调试期间您可以修改之以避免输入地址的麻烦
//#define RTMP_PUBLISH_URL @"rtmp://2157.livepush.myqcloud.com/live/2157_6cfbca22ecad11e5b91fa4dcbef5e35a?bizid=2157"
@interface PublishController ()<UITextFieldDelegate, TXLivePushListener>
@end
@implementation PublishController
{
}
- (void)viewDidLoad {
[super viewDidLoad];
[self initUI];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppDeactive:) name:UIApplicationWillResignActiveNotification object:nil];
_txLivePublisher = [[TXLivePush alloc] init];
[_txLivePublisher setLogLevel:LOGLEVEL_DEBUG];
TXLivePushConfig* _config = [[TXLivePushConfig alloc] init];
[_txLivePublisher setConfig:_config];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma -
-(void) onAppActive:(UIApplication*)app
{
if (_publish_switch == YES) {
[self startRtmp];
}
}
-(void) onAppDeactive:(UIApplication*)app
{
if (_publish_switch == YES) {
[self stopRtmp];
}
}
#pragma -
- (void)clearLog {
_tipsMsg = @"";
_logMsg = @"";
[_statusView setText:@""];
[_logViewEvt setText:@""];
_startTime = [[NSDate date]timeIntervalSince1970]*1000;
_lastTime = _startTime;
}
-(BOOL)startRtmp{
[self clearLog];
NSString* rtmpUrl = self.txtRtmpUrl.text;
if (rtmpUrl.length == 0) {
rtmpUrl = RTMP_PUBLISH_URL;
}
if (!([rtmpUrl hasPrefix:@"http:"] || [rtmpUrl hasPrefix:@"rtmp:"] )) {
[self toastTip:@"请输入正确的推流地址"];
return NO;
}
//是否有摄像头权限
AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
if (status == AVAuthorizationStatusDenied) {
[self toastTip:@"获取摄像头权限失败,请前往隐私-相机设置里面打开应用权限"];
return NO;
}
NSArray* ver = [TXRtmpApi getSDKVersion];
if ([ver count] >= 3) {
_logMsg = [NSString stringWithFormat:@"rtmp sdk version: %@.%@.%@",ver[0],ver[1],ver[2]];
[_logViewEvt setText:_logMsg];
}
if(_txLivePublisher != nil)
{
_txLivePublisher.delegate = self;
[_txLivePublisher startPreview:self.view];
[_txLivePublisher startPush:rtmpUrl];
}
return YES;
}
- (void)stopRtmp {
if(_txLivePublisher != nil)
{
_txLivePublisher.delegate = nil;
[_txLivePublisher stopPreview];
[_txLivePublisher stopPush];
_sdBeauty.value = 0;
_sdWhitening.value = 0;
}
}
// RTMP 推流事件通知
#pragma - TXLivePushListener
-(void) appendLog:(NSString*) evt time:(NSDate*) date mills:(int)mil
{
NSDateFormatter* format = [[NSDateFormatter alloc] init];
format.dateFormat = @"hh:mm:ss";
NSString* time = [format stringFromDate:date];
NSString* log = [NSString stringWithFormat:@"[%@.%-3.3d] %@", time, mil, evt];
if (_logMsg == nil) {
_logMsg = @"";
}
_logMsg = [NSString stringWithFormat:@"%@\n%@", _logMsg, log];
[_logViewEvt setText:_logMsg];
}
-(void) onPushEvent:(int)EvtID WithParam:(NSDictionary*)param;
{
NSDictionary* dict = param;
dispatch_async(dispatch_get_main_queue(), ^{
if (EvtID == PUSH_ERR_NET_DISCONNECT) {
[self clickPublish:_btnPublish];
}
// NSLog(@"evt:%d,%@", EvtID, dict);
long long time = [(NSNumber*)[dict valueForKey:EVT_TIME] longLongValue];
int mil = time % 1000;
NSDate* date = [NSDate dateWithTimeIntervalSince1970:time/1000];
NSString* Msg = (NSString*)[dict valueForKey:EVT_MSG];
[self appendLog:Msg time:date mills:mil];
});
}
-(void) onNetStatus:(NSDictionary*) param
{
NSDictionary* dict = param;
dispatch_async(dispatch_get_main_queue(), ^{
int netspeed = [(NSNumber*)[dict valueForKey:NET_STATUS_NET_SPEED] intValue];
int vbitrate = [(NSNumber*)[dict valueForKey:NET_STATUS_VIDEO_BITRATE] intValue];
int abitrate = [(NSNumber*)[dict valueForKey:NET_STATUS_AUDIO_BITRATE] intValue];
int cachesize = [(NSNumber*)[dict valueForKey:NET_STATUS_CACHE_SIZE] intValue];
int dropsize = [(NSNumber*)[dict valueForKey:NET_STATUS_DROP_SIZE] intValue];
int jitter = [(NSNumber*)[dict valueForKey:NET_STATUS_NET_JITTER] intValue];
int fps = [(NSNumber*)[dict valueForKey:NET_STATUS_VIDEO_FPS] intValue];
int width = [(NSNumber*)[dict valueForKey:NET_STATUS_VIDEO_WIDTH] intValue];
int height = [(NSNumber*)[dict valueForKey:NET_STATUS_VIDEO_HEIGHT] intValue];
float cpu_usage = [(NSNumber*)[dict valueForKey:NET_STATUS_CPU_USAGE] floatValue];
NSString* log = [NSString stringWithFormat:@"CPU:%.1f%%\tRES:%d*%d\tSPD:%dkb/s\nJITT:%d\tFPS:%d\tARA:%dkb/s\nQUE:%d\tDRP:%d\tVRA:%dkb/s",
cpu_usage*100,
width,
height,
netspeed,
jitter,
fps,
abitrate,
cachesize,
dropsize,
vbitrate];
[_statusView setText:log];
});
}
#pragma - ui util
-(void) initUI
{
//主界面排版
[self.view setBackgroundColor:[UIColor orangeColor]];
CGSize size = [[UIScreen mainScreen] bounds].size;
int icon_size = size.width / 10;
_cover = [[UIView alloc]init];
_cover.frame = CGRectMake(10.0f, 55 + 2*icon_size, size.width - 20, size.height - 75 - 3 * icon_size);
_cover.backgroundColor = [UIColor whiteColor];
_cover.alpha = 0.5;
_cover.hidden = YES;
[self.view addSubview:_cover];
int logheadH = 50;
_statusView = [[UITextView alloc] initWithFrame:CGRectMake(10.0f, 55 + 2*icon_size, size.width - 20, logheadH)];
_statusView.backgroundColor = [UIColor clearColor];
_statusView.alpha = 1;
_statusView.textColor = [UIColor blackColor];
_statusView.editable = NO;
_statusView.hidden = YES;
[self.view addSubview:_statusView];
_logViewEvt = [[UITextView alloc] initWithFrame:CGRectMake(10.0f, 55 + 2*icon_size + logheadH, size.width - 20, size.height - 75 - 3 * icon_size - logheadH)];
_logViewEvt.backgroundColor = [UIColor clearColor];
_logViewEvt.alpha = 1;
_logViewEvt.textColor = [UIColor blackColor];
_logViewEvt.editable = NO;
_logViewEvt.hidden = YES;
[self.view addSubview:_logViewEvt];
NSArray *scArray = [[NSArray alloc] initWithObjects:@"推流",@"播放", nil];
UISegmentedControl* scSwitch = [[UISegmentedControl alloc] initWithItems:scArray];
scSwitch.frame = CGRectMake(75, 40, size.width-150, icon_size);
scSwitch.selectedSegmentIndex = 0;
scSwitch.tintColor = [UIColor blackColor];
[scSwitch addTarget:self action:@selector(segmentAction:) forControlEvents:UIControlEventValueChanged];
[self.view addSubview:scSwitch];
[self.txtRtmpUrl setBorderStyle:UITextBorderStyleRoundedRect];
self.txtRtmpUrl = [[UITextField alloc] initWithFrame:CGRectMake(10, 40 + icon_size + 10, size.width- 25 - icon_size, icon_size)];
self.txtRtmpUrl.placeholder = RTMP_PUBLISH_URL;
self.txtRtmpUrl.background = [UIImage imageNamed:@"Input_box"];
self.txtRtmpUrl.alpha = 0.5;
self.txtRtmpUrl.autocapitalizationType = UITextAutocorrectionTypeNo;
self.txtRtmpUrl.delegate = self;
[self.view addSubview:self.txtRtmpUrl];
UIButton* btnScan = [UIButton buttonWithType:UIButtonTypeCustom];
btnScan.frame = CGRectMake(size.width - 10 - icon_size , 40 + icon_size + 10, icon_size, icon_size);
[btnScan setImage:[UIImage imageNamed:@"QR_code"] forState:UIControlStateNormal];
[btnScan addTarget:self action:@selector(clickScan:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btnScan];
int icon_gap = 3*icon_size/8;
//start or stop 按钮
_publish_switch = NO;
_btnPublish = [UIButton buttonWithType:UIButtonTypeCustom];
_btnPublish.frame = CGRectMake(icon_gap, size.height - icon_size - 10, icon_size, icon_size);
[_btnPublish setImage:[UIImage imageNamed:@"start"] forState:UIControlStateNormal];
[_btnPublish addTarget:self action:@selector(clickPublish:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_btnPublish];
//前置后置摄像头切换
_camera_switch = NO;
_btnCamera = [UIButton buttonWithType:UIButtonTypeCustom];
_btnCamera.frame = CGRectMake(2*icon_gap + icon_size, size.height - 10 - icon_size, icon_size, icon_size);
[_btnCamera setImage:[UIImage imageNamed:@"camera"] forState:UIControlStateNormal];
[_btnCamera addTarget:self action:@selector(clickCamera:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_btnCamera];
//美颜开关按钮
_beauty_level = 0;
_btnBeauty = [UIButton buttonWithType:UIButtonTypeCustom];
_btnBeauty.frame = CGRectMake(3*icon_gap + 2*icon_size, size.height - 10 - icon_size, icon_size, icon_size);
[_btnBeauty setImage:[UIImage imageNamed:@"beauty"] forState:UIControlStateNormal];
[_btnBeauty addTarget:self action:@selector(clickBeauty:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_btnBeauty];
//硬件加速
_hardware_switch = NO;
_btnHardware = [UIButton buttonWithType:UIButtonTypeCustom];
_btnHardware.frame = CGRectMake(size.width - 3*icon_gap - 3*icon_size, size.height - 10 - icon_size, icon_size, icon_size);
[_btnHardware setImage:[UIImage imageNamed:@"quick"] forState:UIControlStateNormal];
[_btnHardware addTarget:self action:@selector(clickHardware:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_btnHardware];
//log显示或隐藏
_log_switch = NO;
_btnLog = [UIButton buttonWithType:UIButtonTypeCustom];
_btnLog.frame = CGRectMake(size.width - 2*icon_gap - 2*icon_size, size.height - 10 - icon_size, icon_size, icon_size);
[_btnLog setImage:[UIImage imageNamed:@"log"] forState:UIControlStateNormal];
[_btnLog addTarget:self action:@selector(clickLog:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_btnLog];
//清晰度按钮
_btnResolution = [UIButton buttonWithType:UIButtonTypeCustom];
_btnResolution.frame = CGRectMake(size.width - icon_gap - icon_size, size.height - 10 - icon_size, icon_size, icon_size);
[_btnResolution setImage:[UIImage imageNamed:@"SD"] forState:UIControlStateNormal];
[_btnResolution addTarget:self action:@selector(clickHD:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_btnResolution];
//开启闪关灯按钮
_torch_switch= NO;
_btnTorch = [UIButton buttonWithType:UIButtonTypeCustom];
_btnTorch.frame = CGRectMake(size.width - 4*icon_gap - 4*icon_size, size.height - 10 - icon_size, icon_size, icon_size);
[_btnTorch setImage:[UIImage imageNamed:@"flash_off"] forState:UIControlStateNormal];
[_btnTorch setImage:[UIImage imageNamed:@"flash_on"] forState:UIControlStateSelected];
[_btnTorch addTarget:self action:@selector(clickTorch:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_btnTorch];
//美颜拉杆浮层
_vBeauty = [[UIControl alloc] init];
_vBeauty.frame = CGRectMake(0, size.height-120, size.width, 120);
[_vBeauty setBackgroundColor:[UIColor whiteColor]];
UILabel* txtBeauty = [[UILabel alloc]init];
txtBeauty.frame = CGRectMake(20, 25, 150, 150);
[txtBeauty setText:@"美颜效果"];
[txtBeauty setFont:[UIFont fontWithName:@"" size:14]];
[txtBeauty sizeToFit];
_sdBeauty = [[UISlider alloc] init];
_sdBeauty.frame = CGRectMake(txtBeauty.frame.origin.x + txtBeauty.frame.size.width + 10, 0, size.width - txtBeauty.frame.origin.x - txtBeauty.frame.size.width - 40, 60);
_sdBeauty.minimumValue = 0;
_sdBeauty.maximumValue = 9;
_sdBeauty.value = 0;
_sdBeauty.center = CGPointMake(_sdBeauty.center.x, txtBeauty.center.y);
[_sdBeauty setThumbImage:[UIImage imageNamed:@"circle"] forState:UIControlStateNormal];
[_sdBeauty setMinimumTrackTintColor:[UIColor blackColor]];
[_sdBeauty setMaximumTrackTintColor:[UIColor blackColor]];
[_sdBeauty addTarget:self action:@selector(sliderValueChange:) forControlEvents:UIControlEventValueChanged];
_sdBeauty.tag = 0;
UILabel* txtWhitening = [[UILabel alloc] init];
txtWhitening.frame = CGRectMake(20, txtBeauty.frame.origin.y + txtBeauty.frame.size.height + 25, 150, 150);
[txtWhitening setText:@"美白效果"];
[txtWhitening setFont:[UIFont fontWithName:@"" size:14]];
[txtWhitening sizeToFit];
_sdWhitening = [[UISlider alloc] init];
_sdWhitening.frame = CGRectMake(txtWhitening.frame.origin.x + txtWhitening.frame.size.width + 10, 0, size.width - txtWhitening.frame.origin.x - txtWhitening.frame.size.width - 40, 60);
_sdWhitening.minimumValue = 0;
_sdWhitening.maximumValue = 9;
_sdWhitening.center = CGPointMake(_sdWhitening.center.x, txtWhitening.center.y);
[_sdWhitening setThumbImage:[UIImage imageNamed:@"circle"] forState:UIControlStateNormal];
[_sdWhitening setMinimumTrackTintColor:[UIColor blackColor]];
[_sdWhitening setMaximumTrackTintColor:[UIColor blackColor]];
[_sdWhitening addTarget:self action:@selector(sliderValueChange:) forControlEvents:UIControlEventValueChanged];
_sdWhitening.tag = 1;
[_vBeauty addSubview:txtBeauty];
[_vBeauty addSubview:_sdBeauty];
[_vBeauty addSubview:txtWhitening];
[_vBeauty addSubview:_sdWhitening];
_vBeauty.hidden = YES;
[self.view addSubview: _vBeauty];
// 清晰度选项: 720p - 640 - 640+ (此处使用了三个普通按钮来模拟单选框, 目的是跟android demo 保持界面风格一致)
_vHD = [[UIControl alloc]init];
_vHD.frame = CGRectMake(0, size.height-120, size.width, 120);
[_vHD setBackgroundColor:[UIColor whiteColor]];
UILabel* txtHD= [[UILabel alloc]init];
txtHD.frame = CGRectMake(0, 0, size.width, 50);
[txtHD setText:@"清晰度"];
[txtHD setFont:[UIFont fontWithName:@"" size:14]];
[_vHD addSubview:txtHD];
int gap = 30;
int width = (size.width - gap*2 - 20) / 3;
_radioBtnHD = [UIButton buttonWithType:UIButtonTypeCustom];
_radioBtnHD.frame = CGRectMake(10, 60, width, 40);
[_radioBtnHD setTitle:@"720p" forState:UIControlStateNormal];
[_radioBtnHD addTarget:self action:@selector(changeHD:) forControlEvents:UIControlEventTouchUpInside];
_radioBtnSD = [UIButton buttonWithType:UIButtonTypeCustom];
_radioBtnSD.frame = CGRectMake(10 + gap + width, 60, width, 40);
[_radioBtnSD setTitle:@"640" forState:UIControlStateNormal];
[_radioBtnSD addTarget:self action:@selector(changeHD:) forControlEvents:UIControlEventTouchUpInside];
_radioBtnAUTO = [UIButton buttonWithType:UIButtonTypeCustom];
_radioBtnAUTO.frame = CGRectMake(size.width - 10 - width, 60, width, 40);
[_radioBtnAUTO setTitle:@"640+" forState:UIControlStateNormal];
[_radioBtnAUTO addTarget:self action:@selector(changeHD:) forControlEvents:UIControlEventTouchUpInside];
[_vHD addSubview:_radioBtnHD];
[_vHD addSubview:_radioBtnSD];
[_vHD addSubview:_radioBtnAUTO];
_vHD.hidden = YES;
[self.view addSubview: _vHD];
// DEMO 默认采用 640 * 360 分辨率, 避免在4S等机型上出现编码不足
_hd_level = [self isSuitableMachine] ? HD_LEVEL_720P : HD_LEVEL_640;
[self setHDUI:_hd_level];
#if TARGET_IPHONE_SIMULATOR
[self toastTip:@"iOS模拟器不支持推流和播放,请使用真机体验"];
#endif
}
-(void) setHDUI:(int) level
{
switch (level) {
case HD_LEVEL_720P:
[_radioBtnHD setBackgroundImage:[UIImage imageNamed:@"black"] forState:UIControlStateNormal];
[_radioBtnSD setBackgroundImage:[UIImage imageNamed:@"white"] forState:UIControlStateNormal];
[_radioBtnAUTO setBackgroundImage:[UIImage imageNamed:@"white"] forState:UIControlStateNormal];
[_radioBtnHD setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[_radioBtnSD setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_radioBtnAUTO setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_btnResolution setImage:[UIImage imageNamed:@"HD"] forState:UIControlStateNormal];
break;
case HD_LEVEL_640:
[_radioBtnHD setBackgroundImage:[UIImage imageNamed:@"white"] forState:UIControlStateNormal];
[_radioBtnSD setBackgroundImage:[UIImage imageNamed:@"black"] forState:UIControlStateNormal];
[_radioBtnAUTO setBackgroundImage:[UIImage imageNamed:@"white"] forState:UIControlStateNormal];
[_radioBtnHD setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_radioBtnSD setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[_radioBtnAUTO setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_btnResolution setImage:[UIImage imageNamed:@"SD"] forState:UIControlStateNormal];
break;
case HD_LEVEL_640_PLUS:
[_radioBtnHD setBackgroundImage:[UIImage imageNamed:@"white"] forState:UIControlStateNormal];
[_radioBtnSD setBackgroundImage:[UIImage imageNamed:@"white"] forState:UIControlStateNormal];
[_radioBtnAUTO setBackgroundImage:[UIImage imageNamed:@"black"] forState:UIControlStateNormal];
[_radioBtnHD setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_radioBtnSD setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_radioBtnAUTO setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[_btnResolution setImage:[UIImage imageNamed:@"PU"] forState:UIControlStateNormal];
default:
break;
}
}
#pragma - 事件处理
- (void) segmentAction:(UISegmentedControl*) sc
{
NSInteger idx = sc.selectedSegmentIndex;
if (idx == 1) {
PlayController *vc = [[PlayController alloc] init];
[self.navigationController pushViewController:vc animated:YES];
sc.selectedSegmentIndex = 0;
[_btnPublish setImage:[UIImage imageNamed:@"start"] forState:UIControlStateNormal];
_publish_switch = NO;
[self stopRtmp];
}
}
-(void) clickScan:(UIButton*) btn
{
[_btnPublish setImage:[UIImage imageNamed:@"start"] forState:UIControlStateNormal];
_publish_switch = NO;
[self stopRtmp];
ScanQRController* vc = [[ScanQRController alloc] init];
vc.pvc = self;
[self.navigationController pushViewController:vc animated:NO];
}
-(void) clickPublish:(UIButton*) btn
{
if (_publish_switch == YES) {
[self stopRtmp];
[_btnPublish setImage:[UIImage imageNamed:@"start"] forState:UIControlStateNormal];
_publish_switch = NO;
[[UIApplication sharedApplication] setIdleTimerDisabled:NO];
}
else
{
if(![self startRtmp])
{
return;
}
[_btnPublish setImage:[UIImage imageNamed:@"suspend"] forState:UIControlStateNormal];
_publish_switch = YES;
[[UIApplication sharedApplication] setIdleTimerDisabled:YES];
}
}
-(void) clickCamera:(UIButton*) btn
{
_camera_switch = !_camera_switch;
[btn setImage:[UIImage imageNamed:(_camera_switch? @"camera2" : @"camera")] forState:UIControlStateNormal];
[_txLivePublisher switchCamera];
}
-(void) clickBeauty:(UIButton*) btn
{
_sdBeauty.value = _beauty_level;
_vBeauty.hidden = NO;
}
/**
@method 获取指定宽度width的字符串在UITextView上的高度
@param textView 待计算的UITextView
@param Width 限制字符串显示区域的宽度
@result float 返回的高度
*/
- (float) heightForString:(UITextView *)textView andWidth:(float)width{
CGSize sizeToFit = [textView sizeThatFits:CGSizeMake(width, MAXFLOAT)];
return sizeToFit.height;
}
- (void) toastTip:(NSString*)toastInfo
{
CGRect frameRC = [[UIScreen mainScreen] bounds];
frameRC.origin.y = frameRC.size.height - 110;
frameRC.size.height -= 110;
__block UITextView * toastView = [[UITextView alloc] init];
toastView.editable = NO;
toastView.selectable = NO;
frameRC.size.height = [self heightForString:toastView andWidth:frameRC.size.width];
toastView.frame = frameRC;
toastView.text = toastInfo;
toastView.backgroundColor = [UIColor whiteColor];
toastView.alpha = 0.5;
[self.view addSubview:toastView];
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(){
[toastView removeFromSuperview];
toastView = nil;
});
}
-(void) clickHardware:(UIButton*) btn
{
if ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.0) {
[self toastTip:@"iOS 版本低于8.0,不支持硬件加速."];
return;
}
if(_txLivePublisher != nil) {
if (_publish_switch == YES) {
[self stopRtmp];
}
TXLivePushConfig * configTmp = _txLivePublisher.config;
if (configTmp.enableHWAcceleration == NO)
{
NSString* strTip = @"iOS SDK启用硬件加速.";
if (_publish_switch == YES)
{
strTip = @"iOS SDK启用硬件加速,切换后会重新开始推流";
}
[self toastTip:strTip];
configTmp.enableHWAcceleration = YES;
[btn setImage:[UIImage imageNamed:@"quick"] forState:UIControlStateNormal];
}
else
{
NSString* strTip = @"iOS SDK停止硬件加速.";
if (_publish_switch == YES)
{
strTip = @"iOS SDK停止硬件加速,切换后会重新开始推流";
}
[self toastTip:strTip];
configTmp.enableHWAcceleration = NO;
[btn setImage:[UIImage imageNamed:@"quick2"] forState:UIControlStateNormal];
}
_txLivePublisher.config = configTmp;
if (_publish_switch == YES) {
[self startRtmp];
}
}
}
-(void) clickLog:(UIButton*) btn
{
if (_log_switch == YES)
{
_statusView.hidden = YES;
_logViewEvt.hidden = YES;
[btn setImage:[UIImage imageNamed:@"log"] forState:UIControlStateNormal];
_cover.hidden = YES;
_log_switch = NO;
}
else
{
_statusView.hidden = NO;
_logViewEvt.hidden = NO;
[btn setImage:[UIImage imageNamed:@"log2"] forState:UIControlStateNormal];
_cover.hidden = NO;
_log_switch = YES;
}
}
-(void) clickTorch:(UIButton*) btn
{
if (_txLivePublisher) {
btn.selected = !btn.selected;
_torch_switch = !_torch_switch;
// if (![_txLivePublisher toggleTorch:_torch_switch]) {
// _torch_switch = !_torch_switch;
// [self toastTip:@"闪光灯启动失败"];
// }
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
if (_torch_switch) {
if ([device hasTorch]) {
[device lockForConfiguration:nil];
[device setTorchMode: AVCaptureTorchModeOn];
[device unlockForConfiguration];
}else {
[self toastTip:@"闪光灯启动失败"];
}
}else {
if ([device hasTorch]) {
[device lockForConfiguration:nil];
[device setTorchMode: AVCaptureTorchModeOff];
[device unlockForConfiguration];
}
}
}
}
-(void) clickHD:(UIButton*) btn
{
_vHD.hidden = NO;
}
-(void) changeHD:(UIButton*) btn
{
if ([btn.titleLabel.text isEqualToString:@"720p"] && NO == [self isSuitableMachine]) {
UIAlertView * alert = [[UIAlertView alloc] initWithTitle: @"硬件加速"
message: @"iphone 6 及以上机型适合开启720p!"
delegate: nil
cancelButtonTitle: @"确认"
otherButtonTitles: nil];
[alert show];
return;
}
if (_txLivePublisher == nil) return;
if (_publish_switch == YES) {
[self stopRtmp];
}
if ([btn.titleLabel.text isEqualToString:@"720p"]) {
_hd_level = HD_LEVEL_720P;
TXLivePushConfig* _config = _txLivePublisher.config;
_config.videoBitratePIN = 1500;
_config.videoResolution = [self isSuitableMachine ] ? VIDEO_RESOLUTION_1280_720 : VIDEO_RESOLUTION_960_540;
_config.enableAutoBitrate = NO;
[_txLivePublisher setConfig:_config];
} else if ([btn.titleLabel.text isEqualToString:@"640"]) {
_hd_level = HD_LEVEL_640;
TXLivePushConfig* _config = _txLivePublisher.config;
_config.videoBitratePIN = 800;
_config.videoResolution = VIDEO_RESOLUTION_640_360;
_config.enableAutoBitrate = NO;
[_txLivePublisher setConfig:_config];
} else if ([btn.titleLabel.text isEqualToString:@"640+"]) {
_hd_level = HD_LEVEL_640_PLUS;
TXLivePushConfig* _config = _txLivePublisher.config;
_config.videoBitrateMin = 500;
_config.videoBitrateMax = 1500;
_config.enableAutoBitrate = YES;
_config.videoResolution = VIDEO_RESOLUTION_640_360;
[_txLivePublisher setConfig:_config]; // 此模式下设置bitrate无效
}
[self setHDUI:_hd_level];
_vHD.hidden = YES;
if (_publish_switch == YES) {
[self startRtmp];
}
}
-(void) sliderValueChange:(UISlider*) obj
{
// todo
if (obj.tag == 0) { //美颜
_beauty_level = obj.value;
} else if (obj.tag == 1) { //美白
_whitening_level = obj.value;
}
[_txLivePublisher setBeautyFilterDepth:_beauty_level setWhiteningFilterDepth:_whitening_level];
}
// iphone 6 及以上机型适合开启720p, 否则20帧的帧率可能无法达到, 这种"流畅不足,清晰有余"的效果并不好
-(BOOL) isSuitableMachine
{
int mib[2] = {CTL_HW, HW_MACHINE};
size_t len = 0;
char* machine;
sysctl(mib, 2, NULL, &len, NULL, 0);
machine = (char*)malloc(len);
sysctl(mib, 2, machine, &len, NULL, 0);
NSString* platform = [NSString stringWithCString:machine encoding:NSASCIIStringEncoding];
free(machine);
if ([platform length] > 6) {
NSString * platNum = [NSString stringWithFormat:@"%C", [platform characterAtIndex: 6 ]];
return ([platNum intValue] >= 7);
} else {
return NO;
}
}
#pragma -- UITextFieldDelegate
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[textField resignFirstResponder];
return YES;
}
- (void) touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[self.txtRtmpUrl resignFirstResponder];
_vHD.hidden = YES;
_vBeauty.hidden = YES;
}
@end
//
// ScanQRController.h
// RTMPiOSDemo
//
// Created by 蓝鲸 on 16/4/1.
// Copyright © 2016年 tencent. All rights reserved.
//
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
@interface ScanQRController : UIViewController
{
BOOL _qrResult;
AVCaptureSession * _captureSession;
AVCaptureVideoPreviewLayer *_videoPreviewLayer;
}
@property (nonatomic, retain) UIViewController* pvc;
@end
//
// ScanQRController.m
// RTMPiOSDemo
//
// Created by 蓝鲸 on 16/4/1.
// Copyright © 2016年 tencent. All rights reserved.
//
#import "ScanQRController.h"
#import "PlayController.h"
#import "PublishController.h"
static const char *kScanQRCodeQueueName = "ScanQRCodeQueue";
@interface ScanQRController ()<AVCaptureMetadataOutputObjectsDelegate>
{
}
@end
@implementation ScanQRController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
_qrResult = NO;
[self startScan];
CGSize size = [[UIScreen mainScreen] bounds].size;
int c_x = size.width/2;
int c_y = size.height/2;
int roi = 160/2;
UIView* top = [[UIView alloc] initWithFrame:CGRectMake(0, 0, size.width, c_y - roi)];
top.backgroundColor = [UIColor blackColor];
top.alpha = 0.8;
[self.view addSubview:top];
UIView* left = [[UIView alloc] initWithFrame:CGRectMake(0, c_y - roi, c_x - roi, 2*roi)];
left.backgroundColor = [UIColor blackColor];
left.alpha = 0.8;
[self.view addSubview:left];
UIView* right = [[UIView alloc] initWithFrame:CGRectMake(c_x + roi , c_y-roi, c_x - roi, 2*roi)];
right.backgroundColor = [UIColor blackColor];
right.alpha = 0.8;
[self.view addSubview:right];
UIView* bottom = [[UIView alloc] initWithFrame:CGRectMake(0, c_y + roi, size.width, c_y - roi)];
bottom.backgroundColor = [UIColor blackColor];
bottom.alpha = 0.8;
[self.view addSubview:bottom];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)startScan
{
NSError * error;
AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
if ([captureDevice lockForConfiguration:nil]) {
//对焦模式,自动对焦
if (captureDevice && [captureDevice isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]) {
[captureDevice setFocusMode:AVCaptureFocusModeContinuousAutoFocus];
}
else if(captureDevice && [captureDevice isFocusModeSupported:AVCaptureFocusModeAutoFocus]){
[captureDevice setFocusMode:AVCaptureFocusModeAutoFocus];
}
// 自动白平衡
if (captureDevice && [captureDevice isWhiteBalanceModeSupported:AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance]) {
captureDevice.whiteBalanceMode = AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance;
}
else if (captureDevice && [captureDevice isWhiteBalanceModeSupported:AVCaptureWhiteBalanceModeAutoWhiteBalance]) {
captureDevice.whiteBalanceMode = AVCaptureWhiteBalanceModeAutoWhiteBalance;
}
if (captureDevice && [captureDevice isExposureModeSupported:AVCaptureExposureModeContinuousAutoExposure]) {
captureDevice.exposureMode = AVCaptureExposureModeContinuousAutoExposure;
}
else if (captureDevice && [captureDevice isExposureModeSupported:AVCaptureExposureModeAutoExpose]) {
captureDevice.exposureMode = AVCaptureExposureModeAutoExpose;
}
[captureDevice unlockForConfiguration];
}
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error];
if (!input) {
NSLog(@"%@", [error localizedDescription]);
return ;
}
// 创建会话
_captureSession = [[AVCaptureSession alloc] init];
// 添加输入流
[_captureSession addInput:input];
// 初始化输出流
AVCaptureMetadataOutput *captureMetadataOutput = [[AVCaptureMetadataOutput alloc] init];
// 添加输出流
[_captureSession addOutput:captureMetadataOutput];
// 创建dispatch queue.
dispatch_queue_t dispatchQueue;
dispatchQueue = dispatch_queue_create(kScanQRCodeQueueName, NULL);
[captureMetadataOutput setMetadataObjectsDelegate:self queue:dispatchQueue];
// 设置元数据类型 AVMetadataObjectTypeQRCode
[captureMetadataOutput setMetadataObjectTypes:[NSArray arrayWithObject:AVMetadataObjectTypeQRCode]];
// captureMetadataOutput.rectOfInterest=CGRectMake(0.25,025,0.5, 0.5);
// 创建输出对象
_videoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession];
[_videoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
[_videoPreviewLayer setFrame:self.view.layer.bounds];
[self.view.layer addSublayer:_videoPreviewLayer];
[_captureSession startRunning];
}
- (void)stopScanQRCode {
[_captureSession stopRunning];
_captureSession = nil;
[_videoPreviewLayer removeFromSuperlayer];
_videoPreviewLayer = nil;
}
- (void)handleScanResult:(NSString *)result
{
[self stopScanQRCode];
if (_qrResult) {
return;
}
_qrResult = YES;
if ([self.pvc isKindOfClass:[PlayController class]]) {
PlayController* vc = (PlayController*)self.pvc;
[vc.txtRtmpUrl setText:result];
}
if ([self.pvc isKindOfClass:[PublishController class]]) {
PublishController* vc = (PublishController*)self.pvc;
[vc.txtRtmpUrl setText:result];
}
[self.navigationController popToViewController:self.pvc animated:NO];
}
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
if (metadataObjects.count>0) {
AVMetadataMachineReadableCodeObject *metadataObj = [metadataObjects objectAtIndex:0];
if ([[metadataObj type] isEqualToString:AVMetadataObjectTypeQRCode]) {
[self performSelectorOnMainThread:@selector(handleScanResult:) withObject:metadataObj.stringValue waitUntilDone:NO];
}
}
}
- (void) touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[self stopScanQRCode];
[self.navigationController popViewControllerAnimated:NO];
}
@end
//
// TXLivePlayConfig.h
// TXRTMPSDK
//
// Created by realingzhou on 16/5/31.
//
//
#import <Foundation/NSObject.h>
@interface TXLivePlayConfig : NSObject
//播放器缓存时间 : 单位秒,取值需要大于0
@property (nonatomic, assign) int cacheTime;
//是否自动调整播放器缓存时间 : YES:启用自动调整,自动调整的最大值和最小值可以分别通过修改maxCacheTime和minCacheTime来设置;
// NO:关闭自动调整,采用默认的指定缓存时间(1s),可以通过修改cacheTime来调整缓存时间.
@property (nonatomic, assign) BOOL bAutoAdjustCacheTime;
//播放器缓存自动调整的最大时间 : 单位秒,取值需要大于0
@property (nonatomic, assign) int maxAutoAdjustCacheTime;
//播放器缓存自动调整的最小时间 : 单位秒,取值需要大于0
@property (nonatomic, assign) int minAutoAdjustCacheTime;
//播放器连接重试次数 : 最小值为 1, 最大值为 10, 默认值为 3
@property (nonatomic, assign) int connectRetryCount;
//播放器连接重试间隔 : 单位秒,最小值为 3, 最大值为 30, 默认值为 3
@property (nonatomic, assign) int connectRetryInterval;
@end
\ No newline at end of file
... ...